/**
 * @namespace Oryx name space for different utility methods
 * @name ORYX.Utils
 */

if (!ORYX)
	var ORYX = {};

ORYX.Utils = {
	/**
	 * General helper method for parsing a param out of current location url
	 * 
	 * @example // Current url in Browser => "http://oryx.org?param=value"
	 * ORYX.Utils.getParamFromUrl("param") // => "value"
	 * @param {Object}
	 *            name
	 */
	getParamFromUrl : function(name) {
		name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
		var regexS = "[\\?&]" + name + "=([^&#]*)";
		var regex = new RegExp(regexS);
		var results = regex.exec(window.location.href);
		if (results == null) {
			return null;
		} else {
			return results[1];
		}
	},

	adjustLightness : function() {
		return arguments[0];
	},

	adjustGradient : function(gradient, reference) {

		if (ORYX.CONFIG.DISABLE_GRADIENT && gradient) {

			var col = reference.getAttributeNS(null, "stop-color") || "#ffffff";

			$A(gradient.getElementsByTagName("stop")).each(function(stop) {
						if (stop == reference) {
							return;
						}
						stop.setAttributeNS(null, "stop-color", col);
					});
		}
	}
}
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

XMLNS = {
	ATOM : "http://www.w3.org/2005/Atom",
	XHTML : "http://www.w3.org/1999/xhtml",
	ERDF : "http://purl.org/NET/erdf/profile",
	RDFS : "http://www.w3.org/2000/01/rdf-schema#",
	RDF : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
	RAZIEL : "http://b3mn.org/Raziel",

	SCHEMA : ""
};

// TODO kann kickstart sich vielleicht auch um die erzeugung von paketen/
// namespaces k???mmern? z.b. requireNamespace("ORYX.Core.SVG");
var Kickstart = {
	started : false,
	callbacks : [],
	alreadyLoaded : [],
	PATH : '',

	load : function() {
		Kickstart.kick();
	},

	kick : function() {
		// console.profile("loading");
		if (!Kickstart.started) {
			Kickstart.started = true;
			Kickstart.callbacks.each(function(callback) {
						// call the registered callback asynchronously.
						window.setTimeout(callback, 1);
					});
		}
	},

	register : function(callback) {
		// TODO Add some mutual exclusion between kick and register calls.
		with (Kickstart) {
			if (started)
				window.setTimeout(callback, 1);
			else
				Kickstart.callbacks.push(callback)
		}
	},

	/**
	 * Loads a js, assuring that it has only been downloaded once.
	 * 
	 * @param {String}
	 *            url the script to load.
	 */
	require : function(url) {
		// if not already loaded, include it.
		if (Kickstart.alreadyLoaded.member(url))
			return false;
		return Kickstart.include(url);
	},

	/**
	 * Loads a js, regardless of whether it has only been already downloaded.
	 * 
	 * @param {String}
	 *            url the script to load.
	 */
	include : function(url) {

		// prepare a script tag and place it in html head.
		var head = document.getElementsByTagNameNS(XMLNS.XHTML, 'head')[0];
		var s = document.createElementNS(XMLNS.XHTML, "script");
		s.setAttributeNS(XMLNS.XHTML, 'type', 'text/javascript');
		s.src = Kickstart.PATH + url;

		// TODO macht es sinn, dass neue skript als letztes kind in den head
		// einzubinden (stichwort reihenfolge der skript tags)?
		head.appendChild(s);

		// remember this url.
		Kickstart.alreadyLoaded.push(url);

		return true;
	}
}

// register kickstart as the new onload event listener on current window.
// previous listener(s) are triggered to launch with kickstart.
Event.observe(window, 'load', Kickstart.load);/*
												 * Copyright 2005-2014 Alfresco
												 * Software, Ltd. All rights
												 * reserved. License rights for
												 * this program may be obtained
												 * from Alfresco Software, Ltd.
												 * pursuant to a written
												 * agreement and any use of this
												 * program without such an
												 * agreement is prohibited.
												 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

var ERDF = {

	LITERAL : 0x01,
	RESOURCE : 0x02,
	DELIMITERS : ['.', '-'],
	HASH : '#',
	HYPHEN : "-",

	schemas : [],
	callback : undefined,
	log : undefined,

	init : function(callback) {

		// init logging.
		// ERDF.log = Log4js.getLogger("oryx");
		// ERDF.log.setLevel(Log4js.Level.ALL);
		// ERDF.log.addAppender(new ConsoleAppender(ERDF.log, false));

		// if(ERDF.log.isTraceEnabled())
		// ERDF.log.trace("ERDF Parser is initialized.");

		// register callbacks and default schemas.
		ERDF.callback = callback;
		ERDF.registerSchema('schema', XMLNS.SCHEMA);
		ERDF.registerSchema('rdfs', XMLNS.RDFS);
	},

	run : function() {

		// if(ERDF.log.isTraceEnabled())
		// ERDF.log.trace("ERDF Parser is running.");

		// do the work.
		return ERDF._checkProfile() && ERDF.parse();
	},

	parse : function() {

		// (ERDF.log.isDebugEnabled())
		// ERDF.log.debug("Begin parsing document metadata.");

		// time measuring
		ERDF.__startTime = new Date();

		var bodies = document.getElementsByTagNameNS(XMLNS.XHTML, 'body');
		var subject = {
			type : ERDF.RESOURCE,
			value : ''
		};

		var result = ERDF._parseDocumentMetadata()
				&& ERDF._parseFromTag(bodies[0], subject);

		// time measuring
		ERDF.__stopTime = new Date();

		var duration = (ERDF.__stopTime - ERDF.__startTime) / 1000.;
		// alert('ERDF parsing took ' + duration + ' s.');

		return result;
	},

	_parseDocumentMetadata : function() {

		// get links from head element.
		var heads = document.getElementsByTagNameNS(XMLNS.XHTML, 'head');
		var links = heads[0].getElementsByTagNameNS(XMLNS.XHTML, 'link');
		var metas = heads[0].getElementsByTagNameNS(XMLNS.XHTML, 'meta');

		// process links first, since they could contain schema definitions.
		$A(links).each(function(link) {
			var properties = link.getAttribute('rel');
			var reversedProperties = link.getAttribute('rev');
			var value = link.getAttribute('href');

			ERDF._parseTriplesFrom(ERDF.RESOURCE, '', properties,
					ERDF.RESOURCE, value);

			ERDF._parseTriplesFrom(ERDF.RESOURCE, value, reversedProperties,
					ERDF.RESOURCE, '');
		});

		// continue with metas.
		$A(metas).each(function(meta) {
			var property = meta.getAttribute('name');
			var value = meta.getAttribute('content');

			ERDF._parseTriplesFrom(ERDF.RESOURCE, '', property, ERDF.LITERAL,
					value);
		});

		return true;
	},

	_parseFromTag : function(node, subject, depth) {

		// avoid parsing non-xhtml content.
		if (!node || !node.namespaceURI || node.namespaceURI != XMLNS.XHTML) {
			return;
		}

		// housekeeping.
		if (!depth)
			depth = 0;
		var id = node.getAttribute('id');

		// some logging.
		// if(ERDF.log.isTraceEnabled())
		// ERDF.log.trace(">".times(depth) + " Parsing " + node.nodeName + "
		// ("+node.nodeType+") for data on " +
		// ((subject.type == ERDF.RESOURCE) ? ('&lt;' + subject.value + '&gt;')
		// : '') +
		// ((subject.type == ERDF.LITERAL) ? '"' + subject.value + '"' : ''));

		/* triple finding! */

		// in a-tags...
		if (node.nodeName.endsWith(':a') || node.nodeName == 'a') {
			var properties = node.getAttribute('rel');
			var reversedProperties = node.getAttribute('rev');
			var value = node.getAttribute('href');
			var title = node.getAttribute('title');
			var content = node.textContent;

			// rel triples
			ERDF._parseTriplesFrom(subject.type, subject.value, properties,
					ERDF.RESOURCE, value, function(triple) {
						var label = title ? title : content;

						// label triples
						ERDF._parseTriplesFrom(triple.object.type,
								triple.object.value, 'rdfs.label',
								ERDF.LITERAL, label);
					});

			// rev triples
			ERDF._parseTriplesFrom(subject.type, subject.value,
					reversedProperties, ERDF.RESOURCE, '');

			// type triples
			ERDF._parseTypeTriplesFrom(subject.type, subject.value, properties);

			// in img-tags...
		} else if (node.nodeName.endsWith(':img') || node.nodeName == 'img') {
			var properties = node.getAttribute('class');
			var value = node.getAttribute('src');
			var alt = node.getAttribute('alt');

			ERDF._parseTriplesFrom(subject.type, subject.value, properties,
					ERDF.RESOURCE, value, function(triple) {
						var label = alt;

						// label triples
						ERDF._parseTriplesFrom(triple.object.type,
								triple.object.value, 'rdfs.label',
								ERDF.LITERAL, label);
					});

		}

		// in every tag
		var properties = node.getAttribute('class');
		var title = node.getAttribute('title');
		var content = node.textContent;
		var label = title ? title : content;

		// regular triples
		ERDF._parseTriplesFrom(subject.type, subject.value, properties,
				ERDF.LITERAL, label);

		if (id)
			subject = {
				type : ERDF.RESOURCE,
				value : ERDF.HASH + id
			};

		// type triples
		ERDF._parseTypeTriplesFrom(subject.type, subject.value, properties);

		// parse all children that are element nodes.
		var children = node.childNodes;
		if (children)
			$A(children).each(function(_node) {
						if (_node.nodeType == _node.ELEMENT_NODE)
							ERDF._parseFromTag(_node, subject, depth + 1);
					});
	},

	_parseTriplesFrom : function(subjectType, subject, properties, objectType,
			object, callback) {

		if (!properties)
			return;
		properties.toLowerCase().split(' ').each(function(property) {

			// if(ERDF.log.isTraceEnabled())
			// ERDF.log.trace("Going for property " + property);

			var schema = ERDF.schemas.find(function(schema) {
						return false || ERDF.DELIMITERS.find(
								function(delimiter) {
									return property.startsWith(schema.prefix
											+ delimiter);
								});
					});

			if (schema && object) {
				property = property.substring(schema.prefix.length + 1,
						property.length);
				var triple = ERDF.registerTriple(new ERDF.Resource(subject), {
							prefix : schema.prefix,
							name : property
						}, (objectType == ERDF.RESOURCE)
								? new ERDF.Resource(object)
								: new ERDF.Literal(object));

				if (callback)
					callback(triple);
			}
		});
	},

	_parseTypeTriplesFrom : function(subjectType, subject, properties, callback) {

		if (!properties)
			return;
		properties.toLowerCase().split(' ').each(function(property) {

			// if(ERDF.log.isTraceEnabled())
			// ERDF.log.trace("Going for property " + property);

			var schema = ERDF.schemas.find(function(schema) {
						return false || ERDF.DELIMITERS.find(
								function(delimiter) {
									return property.startsWith(ERDF.HYPHEN
											+ schema.prefix + delimiter);
								});
					});

			if (schema && subject) {
				property = property.substring(schema.prefix.length + 2,
						property.length);
				var triple = ERDF.registerTriple((subjectType == ERDF.RESOURCE)
								? new ERDF.Resource(subject)
								: new ERDF.Literal(subject), {
							prefix : 'rdf',
							name : 'type'
						}, new ERDF.Resource(schema.namespace + property));
				if (callback)
					callback(triple);
			}
		});
	},

	/**
	 * Checks for ERDF profile declaration in head of document.
	 */
	_checkProfile : function() {

		// get profiles from head element.
		var heads = document.getElementsByTagNameNS(XMLNS.XHTML, 'head');
		var profiles = heads[0].getAttribute("profile");
		var found = false;

		// if erdf profile is contained.
		if (profiles && profiles.split(" ").member(XMLNS.ERDF)) {

			// pass check.
			// if(ERDF.log.isTraceEnabled())
			// ERDF.log.trace("Found ERDF profile " + XMLNS.ERDF);
			return true;

		} else {

			// otherwise fail check.
			// if(ERDF.log.isFatalEnabled())
			// ERDF.log.fatal("No ERDF profile found.");
			return false;
		}
	},

	__stripHashes : function(s) {
		return (s && (typeof s.substring == 'function') && s.substring(0, 1) == '#')
				? s.substring(1, s.length)
				: s;
	},

	registerSchema : function(prefix, namespace) {

		// TODO check whether already registered, if so, complain.
		ERDF.schemas.push({
					prefix : prefix,
					namespace : namespace
				});

		// if(ERDF.log.isDebugEnabled())
		// ERDF.log.debug("Prefix '"+prefix+"' for '"+namespace+"'
		// registered.");
	},

	registerTriple : function(subject, predicate, object) {

		// if prefix is schema, this is a schema definition.
		if (predicate.prefix.toLowerCase() == 'schema')
			this.registerSchema(predicate.name, object.value);

		var triple = new ERDF.Triple(subject, predicate, object);
		ERDF.callback(triple);

		// if(ERDF.log.isInfoEnabled())
		// ERDF.log.info(triple)

		// return the registered triple.
		return triple;
	},

	__enhanceObject : function() {

		/* Resource state querying methods */
		this.isResource = function() {
			return this.type == ERDF.RESOURCE
		};
		this.isLocal = function() {
			return this.isResource() && this.value.startsWith('#')
		};
		this.isCurrentDocument = function() {
			return this.isResource() && (this.value == '')
		};

		/* Resource getter methods. */
		this.getId = function() {
			return this.isLocal() ? ERDF.__stripHashes(this.value) : false;
		};

		/* Liiteral state querying methods */
		this.isLiteral = function() {
			return this.type == ERDF.LIITERAL
		};
	},

	serialize : function(literal) {

		if (!literal) {
			return "";
		} else if (literal.constructor == String) {
			return literal;
		} else if (literal.constructor == Boolean) {
			return literal ? 'true' : 'false';
		} else {
			return literal.toString();
		}
	}
};

ERDF.Triple = function(subject, predicate, object) {

	this.subject = subject;
	this.predicate = predicate;
	this.object = object;

	this.toString = function() {

		return "[ERDF.Triple] " + this.subject.toString() + ' '
				+ this.predicate.prefix + ':' + this.predicate.name + ' '
				+ this.object.toString();
	};
};

ERDF.Resource = function(uri) {

	this.type = ERDF.RESOURCE;
	this.value = uri;
	ERDF.__enhanceObject.apply(this);

	this.toString = function() {
		return '&lt;' + this.value + '&gt;';
	}

};

ERDF.Literal = function(literal) {

	this.type = ERDF.LITERAL;
	this.value = ERDF.serialize(literal);
	ERDF.__enhanceObject.apply(this);

	this.toString = function() {
		return '"' + this.value + '"';
	}
};/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/*
 * Save and triple generation behaviour. Use this area to configure data
 * management to your needs.
 */
var USE_ASYNCHRONOUS_REQUESTS = true;
var DISCARD_UNUSED_TRIPLES = true;
var PREFER_SPANS_OVER_DIVS = true;
var PREFER_TITLE_OVER_TEXTNODE = false;
var RESOURCE_ID_PREFIX = 'resource';

var SHOW_DEBUG_ALERTS_WHEN_SAVING = false;
var SHOW_EXTENDED_DEBUG_INFORMATION = false;

/*
 * Back end specific workarounds.
 */

var USE_ARESS_WORKAROUNDS = true;

/*
 * Data management constants. Do not change these, as they are used both
 * internally and externally to communicate on events and to identify command
 * object actions in triple production and embedding rules.
 */

// Resource constants
var RESOURCE_CREATED = 0x01;
var RESOURCE_REMOVED = 0x02;
var RESOURCE_SAVED = 0x04;
var RESOURCE_RELOADED = 0x08;
var RESOURCE_SYNCHRONIZED = 0x10;

// Triple constants
var TRIPLE_REMOVE = 0x01;
var TRIPLE_ADD = 0x02;
var TRIPLE_RELOAD = 0x04;
var TRIPLE_SAVE = 0x08;

var PROCESSDATA_REF = 'processdata';

// HTTP status code constants
//
// // 2xx
// const 200_OK = 'Ok';
// const 201_CREATED = 'Created';
// const 202_ACCEPTED = 'Accepted';
// const 204_NO_CONTENT = 'No Content';
//
// // 3xx
// const 301_MOVED_PERMANENTLY = 'Moved Permanently';
// const 302_MOVED_TEMPORARILY = 'Moved Temporarily';
// const 304_NOT_MODIFIED = 'Not Modified';
//
// // 4xx
// const 400_BAD_REQUEST = 'Bad Request';
// const 401_UNAUTHORIZED = 'Unauthorized';
// const 403_FORBIDDEN = 'Forbidden';
// const 404_NOT_FOUND = 'Not Found';
// const 409_CONFLICT = 'Conflict';
//
// // 5xx
// const 500_INTERNAL_SERVER_ERROR = 'Internal Server Error';
// const 501_NOT_IMPLEMENTED = 'Not Implemented';
// const 502_BAD_GATEWAY = 'Bad Gateway';
// const 503_SERVICE_UNAVAILABLE = 'Service Unavailable';
//
/**
 * The Data Management object. Use this one when interacting with page internal
 * data. Initialize data management by DataManager.init();
 * 
 * @class DataManager
 */
var DataManager = {

	/**
	 * The init method should be called once in the DataManagers lifetime. It
	 * causes the DataManager to initialize itself, the erdf parser, do all
	 * neccessary registrations and configurations, to run the parser and from
	 * then on deliver all resulting triples. No parameters needed are needed in
	 * a call to this method.
	 */
	init : function() {
		ERDF.init(DataManager._registerTriple);
		DataManager.__synclocal();
	},

	/**
	 * This triple array is meant to be the whole knowledge of the DataManager.
	 */
	_triples : [],

	/**
	 * This method is meant for callback from erdf parsing. It is not to be used
	 * in another way than to add triples to the triple store.
	 * 
	 * @param {Object}
	 *            triple the triple to add to the triple store.
	 */
	_registerTriple : function(triple) {
		DataManager._triples.push(triple)
	},

	/**
	 * The __synclocal method is for internal usage only. It performs
	 * synchronization with the local document, that is, the triple store is
	 * adjustet to the content of the document, which could have been changed by
	 * any other applications running on the same page.
	 */
	__synclocal : function() {
		DataManager._triples = [];
		ERDF.run();
	},

	/**
	 * Makes the shape passed into this method synchronize itself with the DOM.
	 * This method returns the shapes resource object for further manipulation.
	 * 
	 * @param {Object}
	 *            shape
	 */
	__synchronizeShape : function(shape) {

		var r = ResourceManager.getResource(shape.resourceId);
		var serialize = shape.serialize();

		// store all serialize values
		serialize.each(function(ser) {

					var resource = (ser.type == 'resource');
					var _triple = new ERDF.Triple(
							new ERDF.Resource(shape.resourceId), {
								prefix : ser.prefix,
								name : ser.name
							}, resource
									? new ERDF.Resource(ser.value)
									: new ERDF.Literal(ser.value));
					DataManager.setObject(_triple);
				});

		return r;
	},

	__storeShape : function(shape) {

		// first synchronize the shape,
		var resource = DataManager.__synchronizeShape(shape);

		// then save the synchronized dom.
		resource.save();
	},

	__forceExistance : function(shape) {

		if (!$(shape.resourceId)) {

			if (!$$('.' + PROCESSDATA_REF)[0])
				DataManager.graft(XMLNS.XHTML, document.getElementsByTagNameNS(
								XMLNS.XHTML, 'body').item(0), ['div', {
									'class' : PROCESSDATA_REF,
									'style' : 'display:none;'
								}]);

			// object is literal
			DataManager.graft(XMLNS.XHTML, $$('.' + PROCESSDATA_REF)[0], [

							'div', {
								'id' : shape.resourceId,
								// This should be done in a more dynamic
								// way!!!!!
								'class' : (shape instanceof ORYX.Core.Canvas)
										? "-oryx-canvas"
										: undefined
							}]);

		} else {
			var resource = $(shape.resourceId)
			var children = $A(resource.childNodes)
			children.each(function(child) {
						resource.removeChild(child);
					});
		};
	},

	__persistShape : function(shape) {

		// a shape serialization.
		var shapeData = shape.serialize();

		// initialize a triple array and construct a shape resource
		// to be used in triple generation.
		var triplesArray = [];
		var shapeResource = new ERDF.Resource(shape.resourceId);

		// remove all triples for this particular shape's resource
		DataManager.removeTriples(DataManager.query(shapeResource, undefined,
				undefined));

		// for each data set in the shape's serialization
		shapeData.each(function(data) {

					// construct a triple's value
					var value = (data.type == 'resource')
							? new ERDF.Resource(data.value)
							: new ERDF.Literal(data.value);

					// construct triple and add it to the DOM.
					DataManager.addTriple(new ERDF.Triple(shapeResource, {
								prefix : data.prefix,
								name : data.name
							}, value));
				});
	},

	__persistDOM : function(facade) {

		// getChildShapes gets all shapes (nodes AND edges), deep flag
		// makes it return a flattened child hierarchy.

		var canvas = facade.getCanvas();
		var shapes = canvas.getChildShapes(true);
		var result = '';

		// persist all shapes.
		shapes.each(function(shape) {
					DataManager.__forceExistance(shape);
				});
		// DataManager.__synclocal();

		DataManager.__renderCanvas(facade);
		result += DataManager.serialize($(ERDF
						.__stripHashes(facade.getCanvas().resourceId)), true);

		shapes.each(function(shape) {

					DataManager.__persistShape(shape);
					result += DataManager.serialize($(ERDF
									.__stripHashes(shape.resourceId)), true);
				});

		// result += DataManager.__renderCanvas(facade);

		return result;
	},

	__renderCanvas : function(facade) {

		var canvas = facade.getCanvas();
		var stencilSets = facade.getStencilSets();
		var shapes = canvas.getChildShapes(true);

		DataManager.__forceExistance(canvas);

		DataManager.__persistShape(canvas);

		var shapeResource = new ERDF.Resource(canvas.resourceId);

		// remove all triples for this particular shape's resource
		DataManager.removeTriples(DataManager.query(shapeResource, undefined,
				undefined));

		DataManager.addTriple(new ERDF.Triple(shapeResource, {
					prefix : "oryx",
					name : "mode"
				}, new ERDF.Literal("writable")));

		DataManager.addTriple(new ERDF.Triple(shapeResource, {
					prefix : "oryx",
					name : "mode"
				}, new ERDF.Literal("fullscreen")));

		stencilSets.values().each(function(stencilset) {
			DataManager.addTriple(new ERDF.Triple(shapeResource, {
						prefix : "oryx",
						name : "stencilset"
					}, new ERDF.Resource(stencilset.source().replace(/&/g,
							"%26"))));

			DataManager.addTriple(new ERDF.Triple(shapeResource, {
						prefix : "oryx",
						name : "ssnamespace"
					}, new ERDF.Resource(stencilset.namespace())));

			stencilset.extensions().keys().each(function(extension) {
						DataManager.addTriple(new ERDF.Triple(shapeResource, {
									prefix : "oryx",
									name : "ssextension"
								}, new ERDF.Literal(extension)));
					});
		});

		shapes.each(function(shape) {
					DataManager.addTriple(new ERDF.Triple(shapeResource, {
								prefix : "oryx",
								name : "render"
							}, new ERDF.Resource("#" + shape.resourceId)));
				});
	},

	__counter : 0,
	__provideId : function() {

		while ($(RESOURCE_ID_PREFIX + DataManager.__counter))
			DataManager.__counter++;

		return RESOURCE_ID_PREFIX + DataManager.__counter;
	},

	serializeDOM : function(facade) {

		return DataManager.__persistDOM(facade);
	},

	syncGlobal : function(facade) {

		return DataManager.__syncglobal(facade);
	},

	/**
	 * This method is used to synchronize local DOM with remote resources. Local
	 * changes are commited to the server, and remote changes are performed to
	 * the local document.
	 * 
	 * @param {Object}
	 *            facade The facade of the editor that holds certain resource
	 *            representations as shapes.
	 */
	__syncglobal : function(facade) {

		// getChildShapes gets all shapes (nodes AND edges), deep flag
		// makes it return a flattened child hierarchy.

		var canvas = facade.getCanvas();
		var shapes = canvas.getChildShapes(true);

		// create dummy resource representations in the dom
		// for all shapes that were newly created.

		shapes.select(function(shape) {

					// select shapes without resource id.

					return !($(shape.resourceId));

				}).each(function(shape) {

			// create new resources for them.
			if (USE_ARESS_WORKAROUNDS) {

				/*
				 * This is a workaround due to a bug in aress. Resources are
				 * ignoring changes to raziel:type property once they are
				 * created. As long as this is not fixed, the resource is now
				 * being created using a randomly guessed id, this temporary id
				 * is then used in references and the appropriate div is being
				 * populated with properties.
				 * 
				 * AFTER THIS PHASE THE DATA IS INCONSISTENT AS REFERENCES POINT
				 * TO IDS THAT ARE UNKNOWN TO THE BACK END.
				 * 
				 * After the resource is actually created in aress, it gets an
				 * id that is persistent. All shapes are then being populated
				 * with the correct id references and stored on the server.
				 * 
				 * AFTER THE SAVE PROCESS HAS RETURNED, THE DATA IS CONSISTENT
				 * REGARDING THE ID REFERENCES AGAIN.
				 */

				var razielType = shape.properties['raziel-type'];

				var div = '<div xmlns="http://www.w3.org/1999/xhtml">'
						+ '<span class="raziel-type">' + razielType
						+ '</span></div>';

				var r = ResourceManager.__createResource(div);
				shape.resourceId = r.id();

			} else {

				var r = ResourceManager.__createResource();
				shape.resourceId = r.id();
			}

		});

		shapes.each(function(shape) {

					// store all shapes.
					DataManager.__storeShape(shape);
				});
	},

	/**
	 * This method serializes a single div into a string that satisfies the
	 * client/server communication protocol. It ingnores all elements that have
	 * an attribute named class that includes 'transient'.
	 * 
	 * @param {Object}
	 *            node the element to serialize.
	 * @param {Object}
	 *            preserveNamespace whether to preserve the parent's namespace.
	 *            If you are not sure about namespaces, provide just the element
	 *            to be serialized.
	 */
	serialize : function(node, preserveNamespace) {

		if (node.nodeType == node.ELEMENT_NODE) {
			// serialize an element node.

			var children = $A(node.childNodes);
			var attributes = $A(node.attributes);
			var clazz = new String(node.getAttribute('class'));
			var ignore = clazz.split(' ').member('transient');

			// ignore transients.

			if (ignore)
				return '';

			// start serialization.

			var result = '<' + node.nodeName;

			// preserve namespace?
			if (!preserveNamespace)
				result += ' xmlns="'
						+ (node.namespaceURI ? node.namespaceURI : XMLNS.XHTML)
						+ '" xmlns:oryx="http://oryx-editor.org"';

			// add all attributes.

			attributes.each(function(attribute) {
						result += ' ' + attribute.nodeName + '="'
								+ attribute.nodeValue + '"';
					});

			// close if no children.

			if (children.length == 0)
				result += '/>';

			else {

				// serialize all children.

				result += '>';
				children.each(function(_node) {
							result += DataManager.serialize(_node, true)
						});
				result += '</' + node.nodeName + '>'
			}

			return result;

		} else if (node.nodeType == node.TEXT_NODE) {

			// serialize a text node.
			return node.nodeValue;
		}

		// TODO serialize cdata areas also.
		// TODO work on namespace awareness.
	},

	addTriple : function(triple) {

		// assert the subject is a resource

		if (!triple.subject.type == ERDF.LITERAL)
			throw 'Cannot add the triple ' + triple.toString()
					+ ' because the subject is not a resource.'

		// get the element which represents this triple's subject.
		var elementId = ERDF.__stripHashes(triple.subject.value);
		var element = $(elementId);

		// assert the subject is inside this document.
		if (!element)
			throw 'Cannot add the triple ' + triple.toString()
					+ ' because the subject "' + elementId
					+ '" is not in the document.';

		if (triple.object.type == ERDF.LITERAL)

			// object is literal
			DataManager.graft(XMLNS.XHTML, element, ['span', {
				'class' : (triple.predicate.prefix + "-" + triple.predicate.name)
			}, triple.object.value.escapeHTML()]);

		else {

			// object is resource
			DataManager.graft(XMLNS.XHTML, element, ['a', {
				'rel' : (triple.predicate.prefix + "-" + triple.predicate.name),
				'href' : triple.object.value
			}]);

		}

		return true;
	},

	removeTriples : function(triples) {

		// alert('Removing ' +triples.length+' triples.');

		// from all the triples select those ...
		var removed = triples.select(

		function(triple) {

					// TODO remove also from triple store.
					// ... that were actually removed.
					return DataManager.__removeTriple(triple);
				});

		// sync and return removed triples.
		// DataManager.__synclocal();
		return removed;
	},

	removeTriple : function(triple) {

		// remember whether the triple was actually removed.
		var result = DataManager.__removeTriple(triple);

		// sync and return removed triples.
		// DataManager.__synclocal();
		return result;
	},

	__removeTriple : function(triple) {

		// assert the subject is a resource
		if (!triple.subject.type == ERDF.LITERAL)

			throw 'Cannot remove the triple ' + triple.toString()
					+ ' because the subject is not a resource.';

		// get the element which represents this triple's subject.
		var elementId = ERDF.__stripHashes(triple.subject.value);
		var element = $(elementId);

		// assert the subject is inside this document.
		if (!element)

			throw 'Cannot remove the triple ' + triple.toString()
					+ ' because the subject is not in the document.';

		if (triple.object.type == ERDF.LITERAL) {

			// continue searching actively for the triple.
			var result = DataManager.__removeTripleRecursively(triple, element);
			return result;
		}
	},

	__removeTripleRecursively : function(triple, continueFrom) {

		// return when this node is not an element node.
		if (continueFrom.nodeType != continueFrom.ELEMENT_NODE)
			return false;

		var classes = new String(continueFrom.getAttribute('class'));
		var children = $A(continueFrom.childNodes);

		if (classes.include(triple.predicate.prefix + '-'
				+ triple.predicate.name)) {

			var content = continueFrom.textContent;
			if ((triple.object.type == ERDF.LITERAL)
					&& (triple.object.value == content))

				continueFrom.parentNode.removeChild(continueFrom);

			return true;

		} else {

			children.each(function(_node) {
						DataManager.__removeTripleRecursively(triple, _node)
					});
			return false;
		}

	},

	/**
	 * graft() function Originally by Sean M. Burke from interglacial.com,
	 * altered for usage with SVG and namespace (xmlns) support. Be sure you
	 * understand xmlns before using this funtion, as it creates all grafted
	 * elements in the xmlns provided by you and all element's attribures in
	 * default xmlns. If you need to graft elements in a certain xmlns and wish
	 * to assign attributes in both that and another xmlns, you will need to do
	 * stepwise grafting, adding non-default attributes yourself or you'll have
	 * to enhance this function. Latter, I would appreciate:
	 * martin???apfelfabrik.de
	 * 
	 * @param {Object}
	 *            namespace The namespace in which elements should be grafted.
	 * @param {Object}
	 *            parent The element that should contain the grafted structure
	 *            after the function returned.
	 * @param {Object}
	 *            t the crafting structure.
	 * @param {Object}
	 *            doc the document in which grafting is performed.
	 */
	graft : function(namespace, parent, t, doc) {

		doc = (doc || (parent && parent.ownerDocument) || document);
		var e;
		if (t === undefined) {
			echo("Can't graft an undefined value");
		} else if (t.constructor == String) {
			e = doc.createTextNode(t);
		} else {
			for (var i = 0; i < t.length; i++) {
				if (i === 0 && t[i].constructor == String) {
					var snared = t[i].match(/^([a-z][a-z0-9]*)\.([^\s\.]+)$/i);
					if (snared) {
						e = doc.createElementNS(namespace, snared[1]);
						e.setAttributeNS(null, 'class', snared[2]);
						continue;
					}
					snared = t[i].match(/^([a-z][a-z0-9]*)$/i);
					if (snared) {
						e = doc.createElementNS(namespace, snared[1]); // but
																		// no
																		// class
						continue;
					}

					// Otherwise:
					e = doc.createElementNS(namespace, "span");
					e.setAttribute(null, "class", "namelessFromLOL");
				}

				if (t[i] === undefined) {
					echo("Can't graft an undefined value in a list!");
				} else if (t[i].constructor == String
						|| t[i].constructor == Array) {
					this.graft(namespace, e, t[i], doc);
				} else if (t[i].constructor == Number) {
					this.graft(namespace, e, t[i].toString(), doc);
				} else if (t[i].constructor == Object) {
					// hash's properties => element's attributes
					for (var k in t[i]) {
						e.setAttributeNS(null, k, t[i][k]);
					}
				} else if (t[i].constructor == Boolean) {
					this.graft(namespace, e, t[i] ? 'true' : 'false', doc);
				} else
					throw "Object " + t[i]
							+ " is inscrutable as an graft arglet.";
			}
		}

		if (parent)
			parent.appendChild(e);

		return Element.extend(e); // return the topmost created node
	},

	setObject : function(triple) {

		/**
		 * Erwartungen von Arvid an diese Funktion: - Es existiert genau ein
		 * triple mit dem Subjekt und Praedikat, das uebergeben wurde, und
		 * dieses haelt uebergebenes Objekt.
		 */

		var triples = DataManager.query(triple.subject, triple.predicate,
				undefined);

		DataManager.removeTriples(triples);

		DataManager.addTriple(triple);

		return true;
	},

	query : function(subject, predicate, object) {

		/*
		 * Typical triple. {value: subject, type: subjectType}, {prefix:
		 * schema.prefix, name: property}, {value: object, type: objectType});
		 */

		return DataManager._triples.select(function(triple) {

					var select = ((subject)
							? (triple.subject.type == subject.type)
									&& (triple.subject.value == subject.value)
							: true);
					if (predicate) {
						select = select
								&& ((predicate.prefix)
										? (triple.predicate.prefix == predicate.prefix)
										: true);
						select = select
								&& ((predicate.name)
										? (triple.predicate.name == predicate.name)
										: true);
					}
					select = select
							&& ((object)
									? (triple.object.type == object.type)
											&& (triple.object.value == object.value)
									: true);
					return select;
				});
	}
}

Kickstart.register(DataManager.init);

function assert(expr, m) {
	if (!expr)
		throw m;
};

function DMCommand(action, triple) {

	// store action and triple.
	this.action = action;
	this.triple = triple;

	this.toString = function() {
		return 'Command(' + action + ', ' + triple + ')';
	};
}

function DMCommandHandler(nextHandler) {

	/**
	 * Private method to set the next handler in the Chain of Responsibility
	 * (see http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern for
	 * details).
	 * 
	 * @param {DMCommandHandler}
	 *            handler The handler that is next in the chain.
	 */
	this.__setNext = function(handler) {
		var _next = this.__next;
		this.__next = nextHandler;
		return _next ? _next : true;
	};
	this.__setNext(nextHandler);

	/**
	 * Invokes the next handler. If there is no next handler, this method
	 * returns false, otherwise it forwards the result of the handling.
	 * 
	 * @param {Object}
	 *            command The command object to be processed.
	 */
	this.__invokeNext = function(command) {
		return this.__next ? this.__next.handle(command) : false;
	};

	/**
	 * Handles a command. The abstract method process() is called with the
	 * command object that has been passed. If the process method catches the
	 * command (returns true on completion), the handle() method returns true.
	 * If the process() method doesn't catch the command, the next handler will
	 * be invoked.
	 * 
	 * @param {Object}
	 *            command The command object to be processed.
	 */
	this.handle = function(command) {
		return this.process(command) ? true : this.__invokeNext(command);
	}

	/**
	 * Empty process() method returning false. If javascript knew abstract class
	 * members, this would be one.
	 * 
	 * @param {Object}
	 *            command The command object to process.
	 */
	this.process = function(command) {
		return false;
	};
};

/**
 * This Handler manages the addition and the removal of meta elements in the
 * head of the document.
 * 
 * @param {DMCommandHandler}
 *            next The handler that is next in the chain.
 */
function MetaTagHandler(next) {

	DMCommandHandler.apply(this, [next]);
	this.process = function(command) {

		with (command.triple) {

			/* assert prerequisites */
			if (!((subject instanceof ERDF.Resource)
					&& (subject.isCurrentDocument()) && (object instanceof ERDF.Literal)))
				return false;
		}

	};
};

var chain = new MetaTagHandler();
var command = new DMCommand(TRIPLE_ADD, new ERDF.Triple(new ERDF.Resource(''),
				'rdf:tool', new ERDF.Literal('')));

/*
 * if(chain.handle(command)) alert('Handled!');
 */

ResourceManager = {

	__corrupt : false,
	__latelyCreatedResource : undefined,
	__listeners : $H(),
	__token : 1,

	addListener : function(listener, mask) {

		if (!(listener instanceof Function))
			throw 'Resource event listener is not a function!';
		if (!(mask))
			throw 'Invalid mask for resource event listener registration.';

		// construct controller and token.
		var controller = {
			listener : listener,
			mask : mask
		};
		var token = ResourceManager.__token++;

		// add new listener.
		ResourceManager.__listeners[token] = controller;

		// return the token generated.
		return token;
	},

	removeListener : function(token) {

		// remove the listener with the token and return it.
		return ResourceManager.__listners.remove(token);
	},

	__Event : function(action, resourceId) {
		this.action = action;
		this.resourceId = resourceId;
	},

	__dispatchEvent : function(event) {

		// get all listeners. for each listener, ...
		ResourceManager.__listeners.values().each(function(controller) {

					// .. if listener subscribed to this type of event ...
					if (event.action & controller.mask)
						return controller.listener(event);
				});
	},

	getResource : function(id) {

		// get all possible resources for this.
		id = ERDF.__stripHashes(id);
		var resources = DataManager.query(new ERDF.Resource('#' + id), {
					prefix : 'raziel',
					name : 'entry'
				}, undefined);

		// check for consistency.
		if ((resources.length == 1) && (resources[0].object.isResource())) {
			var entryUrl = resources[0].object.value;
			return new ResourceManager.__Resource(id, entryUrl);
		}

		// else throw an error message.
		throw ('Resource with id ' + id + ' not recognized as such. ' + ((resources.length > 1)
				? ' There is more than one raziel:entry URL.'
				: ' There is no raziel:entry URL.'));

		return false;
	},

	__createResource : function(alternativeDiv) {

		var collectionUrls = DataManager.query(new ERDF.Resource(''),
				// TODO This will become raziel:collection in near future.
				{
			prefix : 'raziel',
			name : 'collection'
		}, undefined);

		// check for consistency.

		if ((collectionUrls.length == 1)
				&& (collectionUrls[0].object.isResource())) {

			// get the collection url.

			var collectionUrl = collectionUrls[0].object.value;
			var resource = undefined;

			// if there is an old id, serialize the dummy div from there,
			// otherwise create a dummy div on the fly.

			var serialization = alternativeDiv
					? alternativeDiv
					: '<div xmlns="http://www.w3.org/1999/xhtml"></div>';

			ResourceManager.__request('POST', collectionUrl, serialization,

					// on success
					function() {

				// get div and id that have been generated by the server.

				var response = (this.responseXML);
				var div = response.childNodes[0];
				var id = div.getAttribute('id');

				// store div in DOM
				if (!$$('.' + PROCESSDATA_REF)[0])
					DataManager
							.graft(XMLNS.XHTML,
									document.getElementsByTagNameNS(
											XMLNS.XHTML, 'body').item(0), [
											'div', {
												'class' : PROCESSDATA_REF,
												'style' : 'display:none;'
											}]);

				$$('.' + PROCESSDATA_REF)[0].appendChild(div.cloneNode(true));

				// parse local erdf data once more.

				DataManager.__synclocal();

				// get new resource object.

				resource = new ResourceManager.getResource(id);

				// set up an action informing of the creation.

				ResourceManager.__resourceActionSucceeded(this,
						RESOURCE_CREATED, undefined);
			},

			function() {
				ResourceManager.__resourceActionFailed(this, RESOURCE_CREATED,
						undefined);
			}, false);

			return resource;
		}

		// else
		throw 'Could not create resource! raziel:collection URL is missing!';
		return false;

	},

	__Resource : function(id, url) {

		this.__id = id;
		this.__url = url;

		/*
		 * Process URL is no longer needed to refer to the shape element on the
		 * canvas. AReSS uses the id's to gather information on fireing
		 * behaviour now.
		 */

		// // find the process url.
		// var processUrl = undefined;
		//		
		// var urls = DataManager.query(
		// new ERDF.Resource('#'+this.__id),
		// {prefix: 'raziel', name: 'process'},
		// undefined
		// );
		//		
		// if(urls.length == 0) { throw 'The resource with the id ' +id+ ' has
		// no process url.'};
		//		
		// urls.each( function(triple) {
		//			
		// // if there are more urls, use the last one.
		// processUrl = triple.object.value;
		// });
		//		
		// this.__processUrl = processUrl;
		//
		// // convenience function for getting the process url.
		// this.processUrl = function() {
		// return this.__processUrl;
		// }

		// convenience finction for getting the id.
		this.id = function() {
			return this.__id;
		}

		// convenience finction for getting the entry url.
		this.url = function() {
			return this.__url;
		}

		this.reload = function() {
			var _url = this.__url;
			var _id = this.__id;
			ResourceManager.__request('GET', _url, null, function() {
						ResourceManager.__resourceActionSucceeded(this,
								RESOURCE_RELOADED, _id);
					}, function() {
						ResourceManager.__resourceActionFailed(this,
								RESURCE_RELOADED, _id);
					}, USE_ASYNCHRONOUS_REQUESTS);
		};

		this.save = function(synchronize) {
			var _url = this.__url;
			var _id = this.__id;
			data = DataManager.serialize($(_id));
			ResourceManager.__request('PUT', _url, data, function() {
						ResourceManager.__resourceActionSucceeded(this,
								synchronize
										? RESOURCE_SAVED
												| RESOURCE_SYNCHRONIZED
										: RESOURCE_SAVED, _id);
					}, function() {
						ResourceManager.__resourceActionFailed(this,
								synchronize
										? RESOURCE_SAVED
												| RESOURCE_SYNCHRONIZED
										: RESOURCE.SAVED, _id);
					}, USE_ASYNCHRONOUS_REQUESTS);
		};

		this.remove = function() {
			var _url = this.__url;
			var _id = this.__id;
			ResourceManager.__request('DELETE', _url, null, function() {
						ResourceManager.__resourceActionSucceeded(this,
								RESOURCE_REMOVED, _id);
					}, function() {
						ResourceManager.__resourceActionFailed(this,
								RESOURCE_REMOVED, _id);
					}, USE_ASYNCHRONOUS_REQUESTS);
		};
	},

	request : function(url, requestOptions) {

		var options = {
			method : 'get',
			asynchronous : true,
			parameters : {}
		};

		Object.extend(options, requestOptions || {});

		var params = Hash.toQueryString(options.parameters);
		if (params)
			url += (url.include('?') ? '&' : '?') + params;

		return ResourceManager.__request(options.method, url, options.data,
				(options.onSuccess instanceof Function ? function() {
					options.onSuccess(this);
				} : undefined), (options.onFailure instanceof Function
						? function() {
							options.onFailure(this);
						}
						: undefined), options.asynchronous
						&& USE_ASYNCHRONOUS_REQUESTS, options.headers);
	},

	__request : function(method, url, data, success, error, async, headers) {

		// get a request object
		var httpRequest = Try.these(

				/* do the Mozilla/Safari/Opera stuff */
				function() {
			return new XMLHttpRequest();
		},

				/* do the IE stuff */
				function() {
					return new ActiveXObject("Msxml2.XMLHTTP");
				}, function() {
					return new ActiveXObject("Microsoft.XMLHTTP")
				});

		// if there is no request object ...
		if (!httpRequest) {
			if (!this.__corrupt)
				throw 'This browser does not provide any AJAX functionality. You will not be able to use the software provided with the page you are viewing. Please consider installing appropriate extensions.';
			this.__corrupt = true;
			return false;
		}

		if (success instanceof Function)
			httpRequest.onload = success;
		if (error instanceof Function) {
			httpRequest.onerror = error;
		}

		var h = $H(headers)
		h.keys().each(function(key) {

					httpRequest.setRequestHeader(key, h[key]);
				});

		try {

			if (SHOW_DEBUG_ALERTS_WHEN_SAVING)

				alert(method + ' ' + url + '\n'
						+ SHOW_EXTENDED_DEBUG_INFORMATION ? data : '');

			// TODO Remove synchronous calls to the server as soon as xenodot
			// handles asynchronous requests without failure.
			httpRequest.open(method, url, !async ? false : true);
			httpRequest.send(data);

		} catch (e) {
			return false;
		}
		return true;
	},

	__resourceActionSucceeded : function(transport, action, id) {

		var status = transport.status;
		var response = transport.responseText;

		if (SHOW_DEBUG_ALERTS_WHEN_SAVING)

			alert(status + ' ' + url + '\n' + SHOW_EXTENDED_DEBUG_INFORMATION
					? data
					: '');

		// if the status code is not in 2xx, throw an error.
		if (status >= 300)
			throw 'The server responded with an error: '
					+ status
					+ '\n'
					+ (SHOW_EXTENDED_DEBUG_INFORMATION
							? +data
							: 'If you need additional information here, including the data sent by the server, consider setting SHOW_EXTENDED_DEBUG_INFORMATION to true.');

		switch (action) {

			case RESOURCE_REMOVED :

				// get div and id
				var response = (transport.responseXML);
				var div = response.childNodes[0];
				var id = div.getAttribute('id');

				// remove the resource from DOM
				var localDiv = document.getElementById(id);
				localDiv.parentNode.removeChild(localDiv);
				break;

			case RESOURCE_CREATED :

				// nothing remains to be done.
				break;

			case RESOURCE_SAVED | RESOURCE_SYNCHRONIZED :

				DataManager.__synclocal();

			case RESOURCE_SAVED :

				// nothing remains to be done.
				break;

			case RESOURCE_RELOADED :

				// get div and id
				var response = (transport.responseXML);
				var div = response.childNodes[0];
				var id = div.getAttribute('id');

				// remove the local resource representation from DOM
				var localDiv = document.getElementById(id)
				localDiv.parentNode.removeChild(localDiv);

				// store div in DOM
				if (!$$(PROCESSDATA_REF)[0])
					DataManager
							.graft(XMLNS.XHTML,
									document.getElementsByTagNameNS(
											XMLNS.XHTML, 'body').item(0), [
											'div', {
												'class' : PROCESSDATA_REF,
												'style' : 'display:none;'
											}]);

				$$(PROCESSDATA_REF)[0].appendChild(div.cloneNode(true));
				DataManager.__synclocal();
				break;

			default :
				DataManager.__synclocal();

		}

		// dispatch to all listeners ...
		ResourceManager.__dispatchEvent(

				// ... an event describing the change that happened here.
				new ResourceManager.__Event(action, id));
	},

	__resourceActionFailed : function(transport, action, id) {
		throw "Fatal: Resource action failed. There is something horribly "
				+ "wrong with either the server, the transport protocol or your "
				+ "online status. Sure you're online?";
	}
}/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * The super class for all classes in ORYX. Adds some OOP feeling to javascript.
 * See article "Object Oriented Super Class Method Calling with JavaScript" on
 * http://truecode.blogspot.com/2006/08/object-oriented-super-class-method.html
 * for a documentation on this. Fairly good article that points out errors in
 * Douglas Crockford's inheritance and super method calling approach. Worth
 * reading.
 * 
 * @class Clazz
 */
var Clazz = function() {
};

/**
 * Empty constructor.
 * 
 * @methodOf Clazz.prototype
 */
Clazz.prototype.construct = function() {
};

/**
 * Can be used to build up inheritances of classes.
 * 
 * @example
 * var MyClass = Clazz.extend({
 *   construct: function(myParam){
 *     // Do sth.
 *   }
 * });
 * var MySubClass = MyClass.extend({
 *   construct: function(myParam){
 *     // Use this to call constructor of super class
 *     arguments.callee.$.construct.apply(this, arguments);
 *     // Do sth.
 *   }
 * });
 * @param {Object}
 *            def The definition of the new class.
 */
Clazz.extend = function(def) {
	var classDef = function() {
		if (arguments[0] !== Clazz) {
			this.construct.apply(this, arguments);
		}
	};

	var proto = new this(Clazz);
	var superClass = this.prototype;

	for (var n in def) {
		var item = def[n];
		if (item instanceof Function)
			item.$ = superClass;
		proto[n] = item;
	}

	classDef.prototype = proto;

	// Give this new class the same static extend method
	classDef.extend = this.extend;
	return classDef;
};/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX)
	var ORYX = {};

if (!ORYX.CONFIG)
	ORYX.CONFIG = {};

/**
 * This file contains URI constants that may be used for XMLHTTPRequests.
 */

ORYX.CONFIG.ROOT_PATH = "editor/"; // TODO: Remove last slash!!
ORYX.CONFIG.EXPLORER_PATH = "explorer";
ORYX.CONFIG.LIBS_PATH = "libs";

/**
 * Regular Config
 */
ORYX.CONFIG.SERVER_HANDLER_ROOT = "service";
ORYX.CONFIG.SERVER_EDITOR_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor";
ORYX.CONFIG.SERVER_MODEL_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/model";
ORYX.CONFIG.STENCILSET_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/editor_stencilset?embedsvg=true&url=true&namespace=";
ORYX.CONFIG.STENCIL_SETS_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/editor_stencilset";

ORYX.CONFIG.PLUGINS_CONFIG = "editor-app/plugins.xml";
ORYX.CONFIG.SYNTAXCHECKER_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/syntaxchecker";
ORYX.CONFIG.DEPLOY_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/model/deploy";
ORYX.CONFIG.MODEL_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/models";
ORYX.CONFIG.FORM_FLOW_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/formflows";
ORYX.CONFIG.FORM_FLOW_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/formflow";
ORYX.CONFIG.FORM_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/forms";
ORYX.CONFIG.FORM_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/form";
ORYX.CONFIG.SUB_PROCESS_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/subprocesses";
ORYX.CONFIG.SUB_PROCESS_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/subprocess";
ORYX.CONFIG.TEST_SERVICE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/service/";

ORYX.CONFIG.SERVICE_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/services";
ORYX.CONFIG.CONDITION_ELEMENT_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/conditionelements";
ORYX.CONFIG.VARIABLEDEF_ELEMENT_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/variabledefinitionelements";
ORYX.CONFIG.VALIDATOR_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/validators";

ORYX.CONFIG.SS_EXTENSIONS_FOLDER = ORYX.CONFIG.ROOT_PATH
		+ "stencilsets/extensions/";
ORYX.CONFIG.SS_EXTENSIONS_CONFIG = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/editor_ssextensions";
ORYX.CONFIG.ORYX_NEW_URL = "/new";
ORYX.CONFIG.BPMN_LAYOUTER = ORYX.CONFIG.ROOT_PATH + "bpmnlayouter";

ORYX.CONFIG.EXPRESSION_METADATA_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/expression-metadata";
ORYX.CONFIG.DATASOURCE_METADATA_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT
		+ "/datasource-metadata";/*
									 * Copyright 2005-2014 Alfresco Software,
									 * Ltd. All rights reserved. License rights
									 * for this program may be obtained from
									 * Alfresco Software, Ltd. pursuant to a
									 * written agreement and any use of this
									 * program without such an agreement is
									 * prohibited.
									 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX)
	var ORYX = {};

if (!ORYX.CONFIG)
	ORYX.CONFIG = {};

/**
 * Signavio specific variables
 */
ORYX.CONFIG.BACKEND_SWITCH = true;
ORYX.CONFIG.PANEL_LEFT_WIDTH = 250;
ORYX.CONFIG.PANEL_RIGHT_COLLAPSED = true;
ORYX.CONFIG.PANEL_RIGHT_WIDTH = 300;
ORYX.CONFIG.APPNAME = 'KISBPM';
ORYX.CONFIG.WEB_URL = ".";

ORYX.CONFIG.BLANK_IMAGE = ORYX.CONFIG.LIBS_PATH
		+ '/ext-2.0.2/resources/images/default/s.gif';

/* Specify offset of header */
ORYX.CONFIG.OFFSET_HEADER = 61;

/* Show grid line while dragging */
ORYX.CONFIG.SHOW_GRIDLINE = true;

/* Editor-Mode */
ORYX.CONFIG.MODE_READONLY = "readonly";
ORYX.CONFIG.MODE_FULLSCREEN = "fullscreen";
ORYX.CONFIG.WINDOW_HEIGHT = 800;
ORYX.CONFIG.PREVENT_LOADINGMASK_AT_READY = false;

/* Plugins */
ORYX.CONFIG.PLUGINS_ENABLED = true;
ORYX.CONFIG.PLUGINS_FOLDER = "Plugins/";

ORYX.CONFIG.BPMN20_SCHEMA_VALIDATION_ON = true;

/* Namespaces */
ORYX.CONFIG.NAMESPACE_ORYX = "http://www.b3mn.org/oryx";
ORYX.CONFIG.NAMESPACE_SVG = "http://www.w3.org/2000/svg";

/* UI */
ORYX.CONFIG.CANVAS_WIDTH = 1200;
ORYX.CONFIG.CANVAS_HEIGHT = 1050;
ORYX.CONFIG.CANVAS_RESIZE_INTERVAL = 100;
ORYX.CONFIG.CANVAS_MIN_WIDTH = 800;
ORYX.CONFIG.CANVAS_MIN_HEIGHT = 300;
ORYX.CONFIG.SELECTED_AREA_PADDING = 4;
ORYX.CONFIG.CANVAS_BACKGROUND_COLOR = "none";
ORYX.CONFIG.GRID_DISTANCE = 30;
ORYX.CONFIG.GRID_ENABLED = true;
ORYX.CONFIG.ZOOM_OFFSET = 0.1;
ORYX.CONFIG.DEFAULT_SHAPE_MARGIN = 60;
ORYX.CONFIG.SCALERS_SIZE = 7;
ORYX.CONFIG.MINIMUM_SIZE = 20;
ORYX.CONFIG.MAXIMUM_SIZE = 10000;
ORYX.CONFIG.OFFSET_MAGNET = 15;
ORYX.CONFIG.OFFSET_EDGE_LABEL_TOP = 8;
ORYX.CONFIG.OFFSET_EDGE_LABEL_BOTTOM = 8;
ORYX.CONFIG.OFFSET_EDGE_BOUNDS = 5;
ORYX.CONFIG.COPY_MOVE_OFFSET = 30;

ORYX.CONFIG.BORDER_OFFSET = 14;

ORYX.CONFIG.MAX_NUM_SHAPES_NO_GROUP = 20; // Updated so the form editor shows
											// all elements at once

ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER = 30;
ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET = 45;

/* Shape-Menu Align */
ORYX.CONFIG.SHAPEMENU_RIGHT = "Oryx_Right";
ORYX.CONFIG.SHAPEMENU_BOTTOM = "Oryx_Bottom";
ORYX.CONFIG.SHAPEMENU_LEFT = "Oryx_Left";
ORYX.CONFIG.SHAPEMENU_TOP = "Oryx_Top";

/* Morph-Menu Item */
ORYX.CONFIG.MORPHITEM_DISABLED = "Oryx_MorphItem_disabled";

/* Property type names */
ORYX.CONFIG.TYPE_STRING = "string";
ORYX.CONFIG.TYPE_BOOLEAN = "boolean";
ORYX.CONFIG.TYPE_INTEGER = "integer";
ORYX.CONFIG.TYPE_FLOAT = "float";
ORYX.CONFIG.TYPE_COLOR = "color";
ORYX.CONFIG.TYPE_DATE = "date";
ORYX.CONFIG.TYPE_CHOICE = "choice";
ORYX.CONFIG.TYPE_URL = "url";
ORYX.CONFIG.TYPE_DIAGRAM_LINK = "diagramlink";
ORYX.CONFIG.TYPE_COMPLEX = "complex";
ORYX.CONFIG.TYPE_MULTIPLECOMPLEX = "multiplecomplex";
ORYX.CONFIG.TYPE_TEXT = "text";
ORYX.CONFIG.TYPE_KISBPM_MULTIINSTANCE = "kisbpm-multiinstance";
ORYX.CONFIG.TYPE_MODEL_LINK = "modellink";
ORYX.CONFIG.TYPE_FORM_FLOW_LINK = "formflowlink";
ORYX.CONFIG.TYPE_FORM_LINK = "formlink";
ORYX.CONFIG.TYPE_SUB_PROCESS_LINK = "subprocesslink";
ORYX.CONFIG.TYPE_SERVICE_LINK = "servicelink";
ORYX.CONFIG.TYPE_CONDITIONS = "conditions";
ORYX.CONFIG.TYPE_VARIABLES = "variables";
ORYX.CONFIG.TYPE_LISTENER = "listener";
ORYX.CONFIG.TYPE_EPC_FREQ = "epcfrequency";
ORYX.CONFIG.TYPE_GLOSSARY_LINK = "glossarylink";
ORYX.CONFIG.TYPE_EXPRESSION = "expression";
ORYX.CONFIG.TYPE_DATASOURCE = "datasource";
ORYX.CONFIG.TYPE_DATASOURCE_MINIMAL = "datasource-minimal";
ORYX.CONFIG.TYPE_VALIDATORS = "validators";

/* Vertical line distance of multiline labels */
ORYX.CONFIG.LABEL_LINE_DISTANCE = 2;
ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT = 12;

/* Open Morph Menu with Hover */
ORYX.CONFIG.ENABLE_MORPHMENU_BY_HOVER = false;

/* Editor constants come here */
ORYX.CONFIG.EDITOR_ALIGN_BOTTOM = 0x01;
ORYX.CONFIG.EDITOR_ALIGN_MIDDLE = 0x02;
ORYX.CONFIG.EDITOR_ALIGN_TOP = 0x04;
ORYX.CONFIG.EDITOR_ALIGN_LEFT = 0x08;
ORYX.CONFIG.EDITOR_ALIGN_CENTER = 0x10;
ORYX.CONFIG.EDITOR_ALIGN_RIGHT = 0x20;
ORYX.CONFIG.EDITOR_ALIGN_SIZE = 0x30;

/* Event types */
ORYX.CONFIG.EVENT_MOUSEDOWN = "mousedown";
ORYX.CONFIG.EVENT_MOUSEUP = "mouseup";
ORYX.CONFIG.EVENT_MOUSEOVER = "mouseover";
ORYX.CONFIG.EVENT_MOUSEOUT = "mouseout";
ORYX.CONFIG.EVENT_MOUSEMOVE = "mousemove";
ORYX.CONFIG.EVENT_DBLCLICK = "dblclick";
ORYX.CONFIG.EVENT_KEYDOWN = "keydown";
ORYX.CONFIG.EVENT_KEYUP = "keyup";

ORYX.CONFIG.EVENT_LOADED = "editorloaded";
ORYX.CONFIG.EVENT_SAVED = "editorSaved";

ORYX.CONFIG.EVENT_EXECUTE_COMMANDS = "executeCommands";
ORYX.CONFIG.EVENT_STENCIL_SET_LOADED = "stencilSetLoaded";
ORYX.CONFIG.EVENT_SELECTION_CHANGED = "selectionchanged";
ORYX.CONFIG.EVENT_SHAPEADDED = "shapeadded";
ORYX.CONFIG.EVENT_SHAPEREMOVED = "shaperemoved";
ORYX.CONFIG.EVENT_PROPERTY_CHANGED = "propertyChanged";
ORYX.CONFIG.EVENT_DRAGDROP_START = "dragdrop.start";
ORYX.CONFIG.EVENT_SHAPE_MENU_CLOSE = "shape.menu.close";
ORYX.CONFIG.EVENT_DRAGDROP_END = "dragdrop.end";
ORYX.CONFIG.EVENT_RESIZE_START = "resize.start";
ORYX.CONFIG.EVENT_RESIZE_END = "resize.end";
ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED = "dragDocker.docked";
ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW = "highlight.showHighlight";
ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE = "highlight.hideHighlight";
ORYX.CONFIG.EVENT_LOADING_ENABLE = "loading.enable";
ORYX.CONFIG.EVENT_LOADING_DISABLE = "loading.disable";
ORYX.CONFIG.EVENT_LOADING_STATUS = "loading.status";
ORYX.CONFIG.EVENT_OVERLAY_SHOW = "overlay.show";
ORYX.CONFIG.EVENT_OVERLAY_HIDE = "overlay.hide";
ORYX.CONFIG.EVENT_ARRANGEMENT_TOP = "arrangement.setToTop";
ORYX.CONFIG.EVENT_ARRANGEMENT_BACK = "arrangement.setToBack";
ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD = "arrangement.setForward";
ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD = "arrangement.setBackward";
ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED = "propertyWindow.propertyChanged";
ORYX.CONFIG.EVENT_LAYOUT_ROWS = "layout.rows";
ORYX.CONFIG.EVENT_LAYOUT_BPEL = "layout.BPEL";
ORYX.CONFIG.EVENT_LAYOUT_BPEL_VERTICAL = "layout.BPEL.vertical";
ORYX.CONFIG.EVENT_LAYOUT_BPEL_HORIZONTAL = "layout.BPEL.horizontal";
ORYX.CONFIG.EVENT_LAYOUT_BPEL_SINGLECHILD = "layout.BPEL.singlechild";
ORYX.CONFIG.EVENT_LAYOUT_BPEL_AUTORESIZE = "layout.BPEL.autoresize";
ORYX.CONFIG.EVENT_AUTOLAYOUT_LAYOUT = "autolayout.layout";
ORYX.CONFIG.EVENT_UNDO_EXECUTE = "undo.execute";
ORYX.CONFIG.EVENT_UNDO_ROLLBACK = "undo.rollback";
ORYX.CONFIG.EVENT_BUTTON_UPDATE = "toolbar.button.update";
ORYX.CONFIG.EVENT_LAYOUT = "layout.dolayout";
ORYX.CONFIG.EVENT_GLOSSARY_LINK_EDIT = "glossary.link.edit";
ORYX.CONFIG.EVENT_GLOSSARY_SHOW = "glossary.show.info";
ORYX.CONFIG.EVENT_GLOSSARY_NEW = "glossary.show.new";
ORYX.CONFIG.EVENT_DOCKERDRAG = "dragTheDocker";
ORYX.CONFIG.EVENT_CANVAS_SCROLL = "canvas.scroll";

ORYX.CONFIG.EVENT_SHOW_PROPERTYWINDOW = "propertywindow.show";
ORYX.CONFIG.EVENT_ABOUT_TO_SAVE = "file.aboutToSave";

/* Selection Shapes Highlights */
ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE = 5;
ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR = "#4444FF";
ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR2 = "#9999FF";

ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_CORNER = "corner";
ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE = "rectangle";

ORYX.CONFIG.SELECTION_VALID_COLOR = "#00FF00";
ORYX.CONFIG.SELECTION_INVALID_COLOR = "#FF0000";

ORYX.CONFIG.DOCKER_DOCKED_COLOR = "#00FF00";
ORYX.CONFIG.DOCKER_UNDOCKED_COLOR = "#FF0000";
ORYX.CONFIG.DOCKER_SNAP_OFFSET = 10;

/* Copy & Paste */
ORYX.CONFIG.EDIT_OFFSET_PASTE = 10;

/* Key-Codes */
ORYX.CONFIG.KEY_CODE_X = 88;
ORYX.CONFIG.KEY_CODE_C = 67;
ORYX.CONFIG.KEY_CODE_V = 86;
ORYX.CONFIG.KEY_CODE_DELETE = 46;
ORYX.CONFIG.KEY_CODE_META = 224;
ORYX.CONFIG.KEY_CODE_BACKSPACE = 8;
ORYX.CONFIG.KEY_CODE_LEFT = 37;
ORYX.CONFIG.KEY_CODE_RIGHT = 39;
ORYX.CONFIG.KEY_CODE_UP = 38;
ORYX.CONFIG.KEY_CODE_DOWN = 40;

// TODO Determine where the lowercase constants are still used and remove them
// from here.
ORYX.CONFIG.KEY_Code_enter = 12;
ORYX.CONFIG.KEY_Code_left = 37;
ORYX.CONFIG.KEY_Code_right = 39;
ORYX.CONFIG.KEY_Code_top = 38;
ORYX.CONFIG.KEY_Code_bottom = 40;

/* Supported Meta Keys */

ORYX.CONFIG.META_KEY_META_CTRL = "metactrl";
ORYX.CONFIG.META_KEY_ALT = "alt";
ORYX.CONFIG.META_KEY_SHIFT = "shift";

/* Key Actions */

ORYX.CONFIG.KEY_ACTION_DOWN = "down";
ORYX.CONFIG.KEY_ACTION_UP = "up";

/* Form Rowlayouting */
ORYX.CONFIG.FORM_ROW_WIDTH = 350;
ORYX.CONFIG.FORM_GROUP_MARGIN = 5;
ORYX.CONFIG.FORM_GROUP_EMPTY_HEIGHT = 100;

/* Form element types */
ORYX.CONFIG.FORM_ELEMENT_ID_PREFIX = 'http://b3mn.org/stencilset/xforms';
ORYX.CONFIG.FORM_ELEMENT_TYPE_ROOT = 'http://b3mn.org/stencilset/xforms#XForm';
ORYX.CONFIG.FORM_ELEMENT_TYPE_GROUP = 'http://b3mn.org/stencilset/xforms#Group';
ORYX.CONFIG.FORM_ELEMENT_TYPE_REPEATING_GROUP = 'http://b3mn.org/stencilset/xforms#RepeatingGroup';
ORYX.CONFIG.FORM_ELEMENT_TYPE_LABEL_FIELD = 'http://b3mn.org/stencilset/xforms#LabelField';

/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

function printf() {

	var result = arguments[0];
	for (var i = 1; i < arguments.length; i++)
		result = result.replace('%' + (i - 1), arguments[i]);
	return result;
}

// oryx constants.
var ORYX_LOGLEVEL_TRACE = 5;
var ORYX_LOGLEVEL_DEBUG = 4;
var ORYX_LOGLEVEL_INFO = 3;
var ORYX_LOGLEVEL_WARN = 2;
var ORYX_LOGLEVEL_ERROR = 1;
var ORYX_LOGLEVEL_FATAL = 0;
var ORYX_LOGLEVEL = 3;
var ORYX_CONFIGURATION_DELAY = 100;
var ORYX_CONFIGURATION_WAIT_ATTEMPTS = 10;

if (!ORYX)
	var ORYX = {};

ORYX = Object.extend(ORYX, {

	// set the path in the config.js file!!!!
	PATH : ORYX.CONFIG.ROOT_PATH,
	// CONFIGURATION: "config.js",

	URLS : [],

	alreadyLoaded : [],

	configrationRetries : 0,

	Version : '0.1.1',

	availablePlugins : [],

	/**
	 * The ORYX.Log logger.
	 */
	Log : {

		__appenders : [{
			append : function(message) {
				if (typeof(console) !== "undefined"
						&& console.log !== undefined) {
					console.log(message);
				}
			}
		}],

		trace : function() {
			if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_TRACE)
				ORYX.Log.__log('TRACE', arguments);
		},
		debug : function() {
			if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_DEBUG)
				ORYX.Log.__log('DEBUG', arguments);
		},
		info : function() {
			if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_INFO)
				ORYX.Log.__log('INFO', arguments);
		},
		warn : function() {
			if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_WARN)
				ORYX.Log.__log('WARN', arguments);
		},
		error : function() {
			if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_ERROR)
				ORYX.Log.__log('ERROR', arguments);
		},
		fatal : function() {
			if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_FATAL)
				ORYX.Log.__log('FATAL', arguments);
		},

		__log : function(prefix, messageParts) {

			messageParts[0] = (new Date()).getTime() + " " + prefix + " "
					+ messageParts[0];
			var message = printf.apply(null, messageParts);

			ORYX.Log.__appenders.each(function(appender) {
						appender.append(message);
					});
		},

		addAppender : function(appender) {
			ORYX.Log.__appenders.push(appender);
		}
	},

	/**
	 * First bootstrapping layer. The Oryx loading procedure begins. In this
	 * step, all preliminaries that are not in the responsibility of Oryx to be
	 * met have to be checked here, such as the existance of the prototpe
	 * library in the current execution environment. After that, the second
	 * bootstrapping layer is being invoked. Failing to ensure that any
	 * preliminary condition is not met has to fail with an error.
	 */
	load : function() {

		ORYX.Log.debug("Oryx begins loading procedure.");

		// check for prototype
		if ((typeof Prototype == 'undefined')
				|| (typeof Element == 'undefined')
				|| (typeof Element.Methods == 'undefined')
				|| parseFloat(Prototype.Version.split(".")[0] + "."
						+ Prototype.Version.split(".")[1]) < 1.5)

			throw ("Application requires the Prototype JavaScript framework >= 1.5.3");

		ORYX.Log.debug("Prototype > 1.5 found.");

		// continue loading.
		ORYX._load();
	},

	/**
	 * Second bootstrapping layer. The oryx configuration is checked. When not
	 * yet loaded, config.js is being requested from the server. A repeated
	 * error in retrieving the configuration will result in an error to be
	 * thrown after a certain time of retries. Once the configuration is there,
	 * all urls that are registered with oryx loading are being requested from
	 * the server. Once everything is loaded, the third layer is being invoked.
	 */
	_load : function() {
		/*
		 * // if configuration not there already, if(!(ORYX.CONFIG)) {
		 *  // if this is the first attempt... if(ORYX.configrationRetries == 0) {
		 *  // get the path and filename. var configuration = ORYX.PATH +
		 * ORYX.CONFIGURATION;
		 * 
		 * ORYX.Log.debug("Configuration not found, loading from '%0'.",
		 * configuration);
		 *  // require configuration file. Kickstart.require(configuration);
		 *  // else if attempts exceeded ... } else if(ORYX.configrationRetries >=
		 * ORYX_CONFIGURATION_WAIT_ATTEMPTS) {
		 * 
		 * throw "Tried to get configuration" + ORYX_CONFIGURATION_WAIT_ATTEMPTS + "
		 * times from '" + configuration + "'. Giving up."
		 *  } else if(ORYX.configrationRetries > 0){
		 *  // point out how many attempts are left... ORYX.Log.debug("Waiting
		 * once more (%0 attempts left)", (ORYX_CONFIGURATION_WAIT_ATTEMPTS -
		 * ORYX.configrationRetries));
		 *  }
		 *  // any case: continue in a moment with increased retry count.
		 * ORYX.configrationRetries++; window.setTimeout(ORYX._load,
		 * ORYX_CONFIGURATION_DELAY); return; }
		 * 
		 * ORYX.Log.info("Configuration loaded.");
		 *  // load necessary scripts. ORYX.URLS.each(function(url) {
		 * ORYX.Log.debug("Requireing '%0'", url); Kickstart.require(ORYX.PATH +
		 * url) });
		 */
		// configurate logging and load plugins.
		ORYX.loadPlugins();
	},

	/**
	 * Third bootstrapping layer. This is where first the plugin coniguration
	 * file is loaded into oryx, analyzed, and where all plugins are being
	 * requested by the server. Afterwards, all editor instances will be
	 * initialized.
	 */
	loadPlugins : function() {

		// load plugins if enabled.
		if (ORYX.CONFIG.PLUGINS_ENABLED)
			ORYX._loadPlugins()
		else
			ORYX.Log.warn("Ignoring plugins, loading Core only.");

		// init the editor instances.
		init();
	},

	_loadPlugins : function() {

		// load plugin configuration file.
		var source = ORYX.CONFIG.PLUGINS_CONFIG;

		ORYX.Log.debug("Loading plugin configuration from '%0'.", source);

		new Ajax.Request(source, {
			asynchronous : false,
			method : 'get',
			onSuccess : function(result) {

				/*
				 * This is the method that is being called when the plugin
				 * configuration was successfully loaded from the server. The
				 * file has to be processed and the contents need to be
				 * considered for further plugin requireation.
				 */

				ORYX.Log.info("Plugin configuration file loaded.");

				// get plugins.xml content
				var resultXml = result.responseXML;

				// TODO: Describe how properties are handled.
				// Get the globale Properties
				var globalProperties = [];
				var preferences = $A(resultXml
						.getElementsByTagName("properties"));
				preferences.each(function(p) {

					var props = $A(p.childNodes);
					props.each(function(prop) {
								var property = new Hash();

								// get all attributes from the node and set to
								// global properties
								var attributes = $A(prop.attributes)
								attributes.each(function(attr) {
											property[attr.nodeName] = attr.nodeValue
										});
								if (attributes.length > 0) {
									globalProperties.push(property)
								};
							});
				});

				// TODO Why are we using XML if we don't respect structure
				// anyway?
				// for each plugin element in the configuration..
				var plugin = resultXml.getElementsByTagName("plugin");
				$A(plugin).each(function(node) {

					// get all element's attributes.
					// TODO: What about: var pluginData = $H(node.attributes) !?
					var pluginData = new Hash();
					$A(node.attributes).each(function(attr) {
								pluginData[attr.nodeName] = attr.nodeValue
							});

					// ensure there's a name attribute.
					if (!pluginData['name']) {
						ORYX.Log
								.error("A plugin is not providing a name. Ingnoring this plugin.");
						return;
					}

					// ensure there's a source attribute.
					if (!pluginData['source']) {
						ORYX.Log
								.error(
										"Plugin with name '%0' doesn't provide a source attribute.",
										pluginData['name']);
						return;
					}

					// Get all private Properties
					var propertyNodes = node.getElementsByTagName("property");
					var properties = [];
					$A(propertyNodes).each(function(prop) {
								var property = new Hash();

								// Get all Attributes from the Node
								var attributes = $A(prop.attributes)
								attributes.each(function(attr) {
											property[attr.nodeName] = attr.nodeValue
										});
								if (attributes.length > 0) {
									properties.push(property)
								};

							});

					// Set all Global-Properties to the Properties
					properties = properties.concat(globalProperties);

					// Set Properties to Plugin-Data
					pluginData['properties'] = properties;

					// Get the RequieredNodes
					var requireNodes = node.getElementsByTagName("requires");
					var requires;
					$A(requireNodes).each(function(req) {
								var namespace = $A(req.attributes).find(
										function(attr) {
											return attr.name == "namespace"
										})
								if (namespace && namespace.nodeValue) {
									if (!requires) {
										requires = {
											namespaces : []
										}
									}

									requires.namespaces
											.push(namespace.nodeValue)
								}
							});

					// Set Requires to the Plugin-Data, if there is one
					if (requires) {
						pluginData['requires'] = requires;
					}

					// Get the RequieredNodes
					var notUsesInNodes = node.getElementsByTagName("notUsesIn");
					var notUsesIn;
					$A(notUsesInNodes).each(function(not) {
								var namespace = $A(not.attributes).find(
										function(attr) {
											return attr.name == "namespace"
										})
								if (namespace && namespace.nodeValue) {
									if (!notUsesIn) {
										notUsesIn = {
											namespaces : []
										}
									}

									notUsesIn.namespaces
											.push(namespace.nodeValue)
								}
							});

					// Set Requires to the Plugin-Data, if there is one
					if (notUsesIn) {
						pluginData['notUsesIn'] = notUsesIn;
					}

					var url = ORYX.PATH + ORYX.CONFIG.PLUGINS_FOLDER
							+ pluginData['source'];

					ORYX.Log.debug("Requireing '%0'", url);

					// Add the Script-Tag to the Site
					// Kickstart.require(url);

					ORYX.Log.info("Plugin '%0' successfully loaded.",
							pluginData['name']);

					// Add the Plugin-Data to all available Plugins
					ORYX.availablePlugins.push(pluginData);

				});

			},
			onFailure : this._loadPluginsOnFails
		});

	},

	_loadPluginsOnFails : function(result) {

		ORYX.Log.error("Plugin configuration file not available.");
	}
});

/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.SVG) {
	ORYX.Core.SVG = {};
}

/**
 * EditPathHandler
 * 
 * Edit SVG paths' coordinates according to specified from-to movement and
 * horizontal and vertical scaling factors. The resulting path's d attribute is
 * stored in instance variable d.
 * 
 * @constructor
 */
ORYX.Core.SVG.EditPathHandler = Clazz.extend({

			construct : function() {
				arguments.callee.$.construct.apply(this, arguments);

				this.x = 0;
				this.y = 0;
				this.oldX = 0;
				this.oldY = 0;
				this.deltaWidth = 1;
				this.deltaHeight = 1;

				this.d = "";
			},

			/**
			 * init
			 * 
			 * @param {float}
			 *            x Target point's x-coordinate
			 * @param {float}
			 *            y Target point's y-coordinate
			 * @param {float}
			 *            oldX Reference point's x-coordinate
			 * @param {float}
			 *            oldY Reference point's y-coordinate
			 * @param {float}
			 *            deltaWidth Horizontal scaling factor
			 * @param {float}
			 *            deltaHeight Vertical scaling factor
			 */
			init : function(x, y, oldX, oldY, deltaWidth, deltaHeight) {
				this.x = x;
				this.y = y;
				this.oldX = oldX;
				this.oldY = oldY;
				this.deltaWidth = deltaWidth;
				this.deltaHeight = deltaHeight;

				this.d = "";
			},

			/**
			 * editPointsAbs
			 * 
			 * @param {Array}
			 *            points Array of absolutePoints
			 */
			editPointsAbs : function(points) {
				if (points instanceof Array) {
					var newPoints = [];
					var x, y;
					for (var i = 0; i < points.length; i++) {
						x = (parseFloat(points[i]) - this.oldX)
								* this.deltaWidth + this.x;
						i++;
						y = (parseFloat(points[i]) - this.oldY)
								* this.deltaHeight + this.y;
						newPoints.push(x);
						newPoints.push(y);
					}

					return newPoints;
				} else {
					// TODO error
				}
			},

			/**
			 * editPointsRel
			 * 
			 * @param {Array}
			 *            points Array of absolutePoints
			 */
			editPointsRel : function(points) {
				if (points instanceof Array) {
					var newPoints = [];
					var x, y;
					for (var i = 0; i < points.length; i++) {
						x = parseFloat(points[i]) * this.deltaWidth;
						i++;
						y = parseFloat(points[i]) * this.deltaHeight;
						newPoints.push(x);
						newPoints.push(y);
					}

					return newPoints;
				} else {
					// TODO error
				}
			},

			/**
			 * arcAbs - A
			 * 
			 * @param {Number}
			 *            rx
			 * @param {Number}
			 *            ry
			 * @param {Number}
			 *            xAxisRotation
			 * @param {Boolean}
			 *            largeArcFlag
			 * @param {Boolean}
			 *            sweepFlag
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			arcAbs : function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag,
					x, y) {
				var pointsAbs = this.editPointsAbs([x, y]);
				var pointsRel = this.editPointsRel([rx, ry]);

				this.d = this.d.concat(" A" + pointsRel[0] + " " + pointsRel[1]
						+ " " + xAxisRotation + " " + largeArcFlag + " "
						+ sweepFlag + " " + pointsAbs[0] + " " + pointsAbs[1]
						+ " ");
			},

			/**
			 * arcRel - a
			 * 
			 * @param {Number}
			 *            rx
			 * @param {Number}
			 *            ry
			 * @param {Number}
			 *            xAxisRotation
			 * @param {Boolean}
			 *            largeArcFlag
			 * @param {Boolean}
			 *            sweepFlag
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			arcRel : function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag,
					x, y) {
				var pointsRel = this.editPointsRel([rx, ry, x, y]);

				this.d = this.d.concat(" a" + pointsRel[0] + " " + pointsRel[1]
						+ " " + xAxisRotation + " " + largeArcFlag + " "
						+ sweepFlag + " " + pointsRel[2] + " " + pointsRel[3]
						+ " ");
			},

			/**
			 * curvetoCubicAbs - C
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicAbs : function(x1, y1, x2, y2, x, y) {
				var pointsAbs = this.editPointsAbs([x1, y1, x2, y2, x, y]);

				this.d = this.d.concat(" C" + pointsAbs[0] + " " + pointsAbs[1]
						+ " " + pointsAbs[2] + " " + pointsAbs[3] + " "
						+ pointsAbs[4] + " " + pointsAbs[5] + " ");
			},

			/**
			 * curvetoCubicRel - c
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicRel : function(x1, y1, x2, y2, x, y) {
				var pointsRel = this.editPointsRel([x1, y1, x2, y2, x, y]);

				this.d = this.d.concat(" c" + pointsRel[0] + " " + pointsRel[1]
						+ " " + pointsRel[2] + " " + pointsRel[3] + " "
						+ pointsRel[4] + " " + pointsRel[5] + " ");
			},

			/**
			 * linetoHorizontalAbs - H
			 * 
			 * @param {Number}
			 *            x
			 */
			linetoHorizontalAbs : function(x) {
				var pointsAbs = this.editPointsAbs([x, 0]);

				this.d = this.d.concat(" H" + pointsAbs[0] + " ");
			},

			/**
			 * linetoHorizontalRel - h
			 * 
			 * @param {Number}
			 *            x
			 */
			linetoHorizontalRel : function(x) {
				var pointsRel = this.editPointsRel([x, 0]);

				this.d = this.d.concat(" h" + pointsRel[0] + " ");
			},

			/**
			 * linetoAbs - L
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			linetoAbs : function(x, y) {
				var pointsAbs = this.editPointsAbs([x, y]);

				this.d = this.d.concat(" L" + pointsAbs[0] + " " + pointsAbs[1]
						+ " ");
			},

			/**
			 * linetoRel - l
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			linetoRel : function(x, y) {
				var pointsRel = this.editPointsRel([x, y]);

				this.d = this.d.concat(" l" + pointsRel[0] + " " + pointsRel[1]
						+ " ");
			},

			/**
			 * movetoAbs - M
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			movetoAbs : function(x, y) {
				var pointsAbs = this.editPointsAbs([x, y]);

				this.d = this.d.concat(" M" + pointsAbs[0] + " " + pointsAbs[1]
						+ " ");
			},

			/**
			 * movetoRel - m
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			movetoRel : function(x, y) {
				var pointsRel;
				if (this.d === "") {
					pointsRel = this.editPointsAbs([x, y]);
				} else {
					pointsRel = this.editPointsRel([x, y]);
				}

				this.d = this.d.concat(" m" + pointsRel[0] + " " + pointsRel[1]
						+ " ");
			},

			/**
			 * curvetoQuadraticAbs - Q
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticAbs : function(x1, y1, x, y) {
				var pointsAbs = this.editPointsAbs([x1, y1, x, y]);

				this.d = this.d.concat(" Q" + pointsAbs[0] + " " + pointsAbs[1]
						+ " " + pointsAbs[2] + " " + pointsAbs[3] + " ");
			},

			/**
			 * curvetoQuadraticRel - q
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticRel : function(x1, y1, x, y) {
				var pointsRel = this.editPointsRel([x1, y1, x, y]);

				this.d = this.d.concat(" q" + pointsRel[0] + " " + pointsRel[1]
						+ " " + pointsRel[2] + " " + pointsRel[3] + " ");
			},

			/**
			 * curvetoCubicSmoothAbs - S
			 * 
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicSmoothAbs : function(x2, y2, x, y) {
				var pointsAbs = this.editPointsAbs([x2, y2, x, y]);

				this.d = this.d.concat(" S" + pointsAbs[0] + " " + pointsAbs[1]
						+ " " + pointsAbs[2] + " " + pointsAbs[3] + " ");
			},

			/**
			 * curvetoCubicSmoothRel - s
			 * 
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicSmoothRel : function(x2, y2, x, y) {
				var pointsRel = this.editPointsRel([x2, y2, x, y]);

				this.d = this.d.concat(" s" + pointsRel[0] + " " + pointsRel[1]
						+ " " + pointsRel[2] + " " + pointsRel[3] + " ");
			},

			/**
			 * curvetoQuadraticSmoothAbs - T
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticSmoothAbs : function(x, y) {
				var pointsAbs = this.editPointsAbs([x, y]);

				this.d = this.d.concat(" T" + pointsAbs[0] + " " + pointsAbs[1]
						+ " ");
			},

			/**
			 * curvetoQuadraticSmoothRel - t
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticSmoothRel : function(x, y) {
				var pointsRel = this.editPointsRel([x, y]);

				this.d = this.d.concat(" t" + pointsRel[0] + " " + pointsRel[1]
						+ " ");
			},

			/**
			 * linetoVerticalAbs - V
			 * 
			 * @param {Number}
			 *            y
			 */
			linetoVerticalAbs : function(y) {
				var pointsAbs = this.editPointsAbs([0, y]);

				this.d = this.d.concat(" V" + pointsAbs[1] + " ");
			},

			/**
			 * linetoVerticalRel - v
			 * 
			 * @param {Number}
			 *            y
			 */
			linetoVerticalRel : function(y) {
				var pointsRel = this.editPointsRel([0, y]);

				this.d = this.d.concat(" v" + pointsRel[1] + " ");
			},

			/**
			 * closePath - z or Z
			 */
			closePath : function() {
				this.d = this.d.concat(" z");
			}

		});/*
			 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
			 * License rights for this program may be obtained from Alfresco
			 * Software, Ltd. pursuant to a written agreement and any use of
			 * this program without such an agreement is prohibited.
			 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.SVG) {
	ORYX.Core.SVG = {};
}

/**
 * MinMaxPathHandler
 * 
 * Determine the minimum and maximum of a SVG path's absolute coordinates. For
 * relative coordinates the absolute value is computed for consideration. The
 * values are stored in attributes minX, minY, maxX, and maxY.
 * 
 * @constructor
 */
ORYX.Core.SVG.MinMaxPathHandler = Clazz.extend({

			construct : function() {
				arguments.callee.$.construct.apply(this, arguments);

				this.minX = undefined;
				this.minY = undefined;
				this.maxX = undefined;
				this.maxY = undefined;

				this._lastAbsX = undefined;
				this._lastAbsY = undefined;
			},

			/**
			 * Store minimal and maximal coordinates of passed points to
			 * attributes minX, maxX, minY, maxY
			 * 
			 * @param {Array}
			 *            points Array of absolutePoints
			 */
			calculateMinMax : function(points) {
				if (points instanceof Array) {
					var x, y;
					for (var i = 0; i < points.length; i++) {
						x = parseFloat(points[i]);
						i++;
						y = parseFloat(points[i]);

						this.minX = (this.minX !== undefined) ? Math.min(
								this.minX, x) : x;
						this.maxX = (this.maxX !== undefined) ? Math.max(
								this.maxX, x) : x;
						this.minY = (this.minY !== undefined) ? Math.min(
								this.minY, y) : y;
						this.maxY = (this.maxY !== undefined) ? Math.max(
								this.maxY, y) : y;

						this._lastAbsX = x;
						this._lastAbsY = y;
					}
				} else {
					// TODO error
				}
			},

			/**
			 * arcAbs - A
			 * 
			 * @param {Number}
			 *            rx
			 * @param {Number}
			 *            ry
			 * @param {Number}
			 *            xAxisRotation
			 * @param {Boolean}
			 *            largeArcFlag
			 * @param {Boolean}
			 *            sweepFlag
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			arcAbs : function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag,
					x, y) {
				this.calculateMinMax([x, y]);
			},

			/**
			 * arcRel - a
			 * 
			 * @param {Number}
			 *            rx
			 * @param {Number}
			 *            ry
			 * @param {Number}
			 *            xAxisRotation
			 * @param {Boolean}
			 *            largeArcFlag
			 * @param {Boolean}
			 *            sweepFlag
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			arcRel : function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag,
					x, y) {
				this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * curvetoCubicAbs - C
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicAbs : function(x1, y1, x2, y2, x, y) {
				this.calculateMinMax([x1, y1, x2, y2, x, y]);
			},

			/**
			 * curvetoCubicRel - c
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicRel : function(x1, y1, x2, y2, x, y) {
				this.calculateMinMax([this._lastAbsX + x1, this._lastAbsY + y1,
						this._lastAbsX + x2, this._lastAbsY + y2,
						this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * linetoHorizontalAbs - H
			 * 
			 * @param {Number}
			 *            x
			 */
			linetoHorizontalAbs : function(x) {
				this.calculateMinMax([x, this._lastAbsY]);
			},

			/**
			 * linetoHorizontalRel - h
			 * 
			 * @param {Number}
			 *            x
			 */
			linetoHorizontalRel : function(x) {
				this.calculateMinMax([this._lastAbsX + x, this._lastAbsY]);
			},

			/**
			 * linetoAbs - L
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			linetoAbs : function(x, y) {
				this.calculateMinMax([x, y]);
			},

			/**
			 * linetoRel - l
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			linetoRel : function(x, y) {
				this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * movetoAbs - M
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			movetoAbs : function(x, y) {
				this.calculateMinMax([x, y]);
			},

			/**
			 * movetoRel - m
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			movetoRel : function(x, y) {
				if (this._lastAbsX && this._lastAbsY) {
					this.calculateMinMax([this._lastAbsX + x,
							this._lastAbsY + y]);
				} else {
					this.calculateMinMax([x, y]);
				}
			},

			/**
			 * curvetoQuadraticAbs - Q
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticAbs : function(x1, y1, x, y) {
				this.calculateMinMax([x1, y1, x, y]);
			},

			/**
			 * curvetoQuadraticRel - q
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticRel : function(x1, y1, x, y) {
				this.calculateMinMax([this._lastAbsX + x1, this._lastAbsY + y1,
						this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * curvetoCubicSmoothAbs - S
			 * 
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicSmoothAbs : function(x2, y2, x, y) {
				this.calculateMinMax([x2, y2, x, y]);
			},

			/**
			 * curvetoCubicSmoothRel - s
			 * 
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicSmoothRel : function(x2, y2, x, y) {
				this.calculateMinMax([this._lastAbsX + x2, this._lastAbsY + y2,
						this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * curvetoQuadraticSmoothAbs - T
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticSmoothAbs : function(x, y) {
				this.calculateMinMax([x, y]);
			},

			/**
			 * curvetoQuadraticSmoothRel - t
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticSmoothRel : function(x, y) {
				this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * linetoVerticalAbs - V
			 * 
			 * @param {Number}
			 *            y
			 */
			linetoVerticalAbs : function(y) {
				this.calculateMinMax([this._lastAbsX, y]);
			},

			/**
			 * linetoVerticalRel - v
			 * 
			 * @param {Number}
			 *            y
			 */
			linetoVerticalRel : function(y) {
				this.calculateMinMax([this._lastAbsX, this._lastAbsY + y]);
			},

			/**
			 * closePath - z or Z
			 */
			closePath : function() {
				return;// do nothing
			}

		});/*
			 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
			 * License rights for this program may be obtained from Alfresco
			 * Software, Ltd. pursuant to a written agreement and any use of
			 * this program without such an agreement is prohibited.
			 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.SVG) {
	ORYX.Core.SVG = {};
}

/**
 * PathHandler
 * 
 * Determine absolute points of a SVG path. The coordinates are stored
 * sequentially in the attribute points (x-coordinates at even indices,
 * y-coordinates at odd indices).
 * 
 * @constructor
 */
ORYX.Core.SVG.PointsPathHandler = Clazz.extend({

			construct : function() {
				arguments.callee.$.construct.apply(this, arguments);

				this.points = [];

				this._lastAbsX = undefined;
				this._lastAbsY = undefined;
			},

			/**
			 * addPoints
			 * 
			 * @param {Array}
			 *            points Array of absolutePoints
			 */
			addPoints : function(points) {
				if (points instanceof Array) {
					var x, y;
					for (var i = 0; i < points.length; i++) {
						x = parseFloat(points[i]);
						i++;
						y = parseFloat(points[i]);

						this.points.push(x);
						this.points.push(y);
						// this.points.push({x:x, y:y});

						this._lastAbsX = x;
						this._lastAbsY = y;
					}
				} else {
					// TODO error
				}
			},

			/**
			 * arcAbs - A
			 * 
			 * @param {Number}
			 *            rx
			 * @param {Number}
			 *            ry
			 * @param {Number}
			 *            xAxisRotation
			 * @param {Boolean}
			 *            largeArcFlag
			 * @param {Boolean}
			 *            sweepFlag
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			arcAbs : function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag,
					x, y) {
				this.addPoints([x, y]);
			},

			/**
			 * arcRel - a
			 * 
			 * @param {Number}
			 *            rx
			 * @param {Number}
			 *            ry
			 * @param {Number}
			 *            xAxisRotation
			 * @param {Boolean}
			 *            largeArcFlag
			 * @param {Boolean}
			 *            sweepFlag
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			arcRel : function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag,
					x, y) {
				this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * curvetoCubicAbs - C
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicAbs : function(x1, y1, x2, y2, x, y) {
				this.addPoints([x, y]);
			},

			/**
			 * curvetoCubicRel - c
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicRel : function(x1, y1, x2, y2, x, y) {
				this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * linetoHorizontalAbs - H
			 * 
			 * @param {Number}
			 *            x
			 */
			linetoHorizontalAbs : function(x) {
				this.addPoints([x, this._lastAbsY]);
			},

			/**
			 * linetoHorizontalRel - h
			 * 
			 * @param {Number}
			 *            x
			 */
			linetoHorizontalRel : function(x) {
				this.addPoints([this._lastAbsX + x, this._lastAbsY]);
			},

			/**
			 * linetoAbs - L
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			linetoAbs : function(x, y) {
				this.addPoints([x, y]);
			},

			/**
			 * linetoRel - l
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			linetoRel : function(x, y) {
				this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * movetoAbs - M
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			movetoAbs : function(x, y) {
				this.addPoints([x, y]);
			},

			/**
			 * movetoRel - m
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			movetoRel : function(x, y) {
				if (this._lastAbsX && this._lastAbsY) {
					this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
				} else {
					this.addPoints([x, y]);
				}
			},

			/**
			 * curvetoQuadraticAbs - Q
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticAbs : function(x1, y1, x, y) {
				this.addPoints([x, y]);
			},

			/**
			 * curvetoQuadraticRel - q
			 * 
			 * @param {Number}
			 *            x1
			 * @param {Number}
			 *            y1
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticRel : function(x1, y1, x, y) {
				this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * curvetoCubicSmoothAbs - S
			 * 
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicSmoothAbs : function(x2, y2, x, y) {
				this.addPoints([x, y]);
			},

			/**
			 * curvetoCubicSmoothRel - s
			 * 
			 * @param {Number}
			 *            x2
			 * @param {Number}
			 *            y2
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoCubicSmoothRel : function(x2, y2, x, y) {
				this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * curvetoQuadraticSmoothAbs - T
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticSmoothAbs : function(x, y) {
				this.addPoints([x, y]);
			},

			/**
			 * curvetoQuadraticSmoothRel - t
			 * 
			 * @param {Number}
			 *            x
			 * @param {Number}
			 *            y
			 */
			curvetoQuadraticSmoothRel : function(x, y) {
				this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
			},

			/**
			 * linetoVerticalAbs - V
			 * 
			 * @param {Number}
			 *            y
			 */
			linetoVerticalAbs : function(y) {
				this.addPoints([this._lastAbsX, y]);
			},

			/**
			 * linetoVerticalRel - v
			 * 
			 * @param {Number}
			 *            y
			 */
			linetoVerticalRel : function(y) {
				this.addPoints([this._lastAbsX, this._lastAbsY + y]);
			},

			/**
			 * closePath - z or Z
			 */
			closePath : function() {
				return;// do nothing
			}

		});/*
			 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
			 * License rights for this program may be obtained from Alfresco
			 * Software, Ltd. pursuant to a written agreement and any use of
			 * this program without such an agreement is prohibited.
			 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * 
 * Config variables
 */
NAMESPACE_ORYX = "http://www.b3mn.org/oryx";
NAMESPACE_SVG = "http://www.w3.org/2000/svg/";

/**
 * @classDescription This class wraps the manipulation of a SVG marker.
 * @namespace ORYX.Core.SVG uses Inheritance (Clazz) uses Prototype 1.5.0
 * 
 */

/**
 * Init package
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.SVG) {
	ORYX.Core.SVG = {};
}

ORYX.Core.SVG.SVGMarker = Clazz.extend({

	/**
	 * Constructor
	 * 
	 * @param markerElement
	 *            {SVGMarkerElement}
	 */
	construct : function(markerElement) {
		arguments.callee.$.construct.apply(this, arguments);

		this.id = undefined;
		this.element = markerElement;
		this.refX = undefined;
		this.refY = undefined;
		this.markerWidth = undefined;
		this.markerHeight = undefined;
		this.oldRefX = undefined;
		this.oldRefY = undefined;
		this.oldMarkerWidth = undefined;
		this.oldMarkerHeight = undefined;
		this.optional = false;
		this.enabled = true;
		this.minimumLength = undefined;
		this.resize = false;

		this.svgShapes = [];

		this._init(); // initialisation of all the properties declared above.
	},

	/**
	 * Initializes the values that are defined in the constructor.
	 */
	_init : function() {
		// check if this.element is a SVGMarkerElement
		if (!(this.element == "[object SVGMarkerElement]")) {
			throw "SVGMarker: Argument is not an instance of SVGMarkerElement.";
		}

		this.id = this.element.getAttributeNS(null, "id");

		// init svg marker attributes
		var refXValue = this.element.getAttributeNS(null, "refX");
		if (refXValue) {
			this.refX = parseFloat(refXValue);
		} else {
			this.refX = 0;
		}
		var refYValue = this.element.getAttributeNS(null, "refY");
		if (refYValue) {
			this.refY = parseFloat(refYValue);
		} else {
			this.refY = 0;
		}
		var markerWidthValue = this.element.getAttributeNS(null, "markerWidth");
		if (markerWidthValue) {
			this.markerWidth = parseFloat(markerWidthValue);
		} else {
			this.markerWidth = 3;
		}
		var markerHeightValue = this.element.getAttributeNS(null,
				"markerHeight");
		if (markerHeightValue) {
			this.markerHeight = parseFloat(markerHeightValue);
		} else {
			this.markerHeight = 3;
		}

		this.oldRefX = this.refX;
		this.oldRefY = this.refY;
		this.oldMarkerWidth = this.markerWidth;
		this.oldMarkerHeight = this.markerHeight;

		// init oryx attributes
		var optionalAttr = this.element.getAttributeNS(NAMESPACE_ORYX,
				"optional");
		if (optionalAttr) {
			optionalAttr = optionalAttr.strip();
			this.optional = (optionalAttr.toLowerCase() === "yes");
		} else {
			this.optional = false;
		}

		var enabledAttr = this.element
				.getAttributeNS(NAMESPACE_ORYX, "enabled");
		if (enabledAttr) {
			enabledAttr = enabledAttr.strip();
			this.enabled = !(enabledAttr.toLowerCase() === "no");
		} else {
			this.enabled = true;
		}

		var minLengthAttr = this.element.getAttributeNS(NAMESPACE_ORYX,
				"minimumLength");
		if (minLengthAttr) {
			this.minimumLength = parseFloat(minLengthAttr);
		}

		var resizeAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resize");
		if (resizeAttr) {
			resizeAttr = resizeAttr.strip();
			this.resize = (resizeAttr.toLowerCase() === "yes");
		} else {
			this.resize = false;
		}

		// init SVGShape objects
		// this.svgShapes = this._getSVGShapes(this.element);
	},

	/**
	 * 
	 */
	_getSVGShapes : function(svgElement) {
		if (svgElement.hasChildNodes) {
			var svgShapes = [];
			var me = this;
			$A(svgElement.childNodes).each(function(svgChild) {
						try {
							var svgShape = new ORYX.Core.SVG.SVGShape(svgChild);
							svgShapes.push(svgShape);
						} catch (e) {
							svgShapes = svgShapes.concat(me
									._getSVGShapes(svgChild));
						}
					});
			return svgShapes;
		}
	},

	/**
	 * Writes the changed values into the SVG marker.
	 */
	update : function() {
		// TODO mache marker resizebar!!! aber erst wenn der rest der
		// connectingshape funzt!

		// //update marker attributes
		// if(this.refX != this.oldRefX) {
		// this.element.setAttributeNS(null, "refX", this.refX);
		// }
		// if(this.refY != this.oldRefY) {
		// this.element.setAttributeNS(null, "refY", this.refY);
		// }
		// if(this.markerWidth != this.oldMarkerWidth) {
		// this.element.setAttributeNS(null, "markerWidth", this.markerWidth);
		// }
		// if(this.markerHeight != this.oldMarkerHeight) {
		// this.element.setAttributeNS(null, "markerHeight", this.markerHeight);
		// }
		//
		// //update SVGShape objects
		// var widthDelta = this.markerWidth / this.oldMarkerWidth;
		// var heightDelta = this.markerHeight / this.oldMarkerHeight;
		// if(widthDelta != 1 && heightDelta != 1) {
		// this.svgShapes.each(function(svgShape) {
		//
		// });
		// }

		// update old values to prepare the next update
		this.oldRefX = this.refX;
		this.oldRefY = this.refY;
		this.oldMarkerWidth = this.markerWidth;
		this.oldMarkerHeight = this.markerHeight;
	},

	toString : function() {
		return (this.element) ? "SVGMarker " + this.element.id : "SVGMarker "
				+ this.element;
	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * 
 * Config variables
 */
NAMESPACE_ORYX = "http://www.b3mn.org/oryx";
NAMESPACE_SVG = "http://www.w3.org/2000/svg/";

/**
 * @classDescription This class wraps the manipulation of a SVG basic shape or a
 *                   path.
 * @namespace ORYX.Core.SVG uses Inheritance (Clazz) uses Prototype 1.5.0 uses
 *            PathParser by Kevin Lindsey (http://kevlindev.com/) uses
 *            MinMaxPathHandler uses EditPathHandler
 * 
 */

// init package
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.SVG) {
	ORYX.Core.SVG = {};
}

ORYX.Core.SVG.SVGShape = Clazz.extend({

	/**
	 * Constructor
	 * 
	 * @param svgElem
	 *            {SVGElement} An SVGElement that is a basic shape or a path.
	 */
	construct : function(svgElem) {
		arguments.callee.$.construct.apply(this, arguments);

		this.type;
		this.element = svgElem;
		this.x = undefined;
		this.y = undefined;
		this.width = undefined;
		this.height = undefined;
		this.oldX = undefined;
		this.oldY = undefined;
		this.oldWidth = undefined;
		this.oldHeight = undefined;
		this.radiusX = undefined;
		this.radiusY = undefined;
		this.isHorizontallyResizable = false;
		this.isVerticallyResizable = false;
		// this.anchors = [];
		this.anchorLeft = false;
		this.anchorRight = false;
		this.anchorTop = false;
		this.anchorBottom = false;

		// attributes of path elements of edge objects
		this.allowDockers = true;
		this.resizeMarkerMid = false;

		this.editPathParser;
		this.editPathHandler;

		this.init(); // initialisation of all the properties declared above.
	},

	/**
	 * Initializes the values that are defined in the constructor.
	 */
	init : function() {

		/** initialize position and size */
		if (ORYX.Editor.checkClassType(this.element, SVGRectElement)
				|| ORYX.Editor.checkClassType(this.element, SVGImageElement)) {
			this.type = "Rect";

			var xAttr = this.element.getAttributeNS(null, "x");
			if (xAttr) {
				this.oldX = parseFloat(xAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var yAttr = this.element.getAttributeNS(null, "y");
			if (yAttr) {
				this.oldY = parseFloat(yAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var widthAttr = this.element.getAttributeNS(null, "width");
			if (widthAttr) {
				this.oldWidth = parseFloat(widthAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var heightAttr = this.element.getAttributeNS(null, "height");
			if (heightAttr) {
				this.oldHeight = parseFloat(heightAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}

		} else if (ORYX.Editor.checkClassType(this.element, SVGCircleElement)) {
			this.type = "Circle";

			var cx = undefined;
			var cy = undefined;
			// var r = undefined;

			var cxAttr = this.element.getAttributeNS(null, "cx");
			if (cxAttr) {
				cx = parseFloat(cxAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var cyAttr = this.element.getAttributeNS(null, "cy");
			if (cyAttr) {
				cy = parseFloat(cyAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var rAttr = this.element.getAttributeNS(null, "r");
			if (rAttr) {
				// r = parseFloat(rAttr);
				this.radiusX = parseFloat(rAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			this.oldX = cx - this.radiusX;
			this.oldY = cy - this.radiusX;
			this.oldWidth = 2 * this.radiusX;
			this.oldHeight = 2 * this.radiusX;

		} else if (ORYX.Editor.checkClassType(this.element, SVGEllipseElement)) {
			this.type = "Ellipse";

			var cx = undefined;
			var cy = undefined;
			// var rx = undefined;
			// var ry = undefined;
			var cxAttr = this.element.getAttributeNS(null, "cx");
			if (cxAttr) {
				cx = parseFloat(cxAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var cyAttr = this.element.getAttributeNS(null, "cy");
			if (cyAttr) {
				cy = parseFloat(cyAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var rxAttr = this.element.getAttributeNS(null, "rx");
			if (rxAttr) {
				this.radiusX = parseFloat(rxAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var ryAttr = this.element.getAttributeNS(null, "ry");
			if (ryAttr) {
				this.radiusY = parseFloat(ryAttr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			this.oldX = cx - this.radiusX;
			this.oldY = cy - this.radiusY;
			this.oldWidth = 2 * this.radiusX;
			this.oldHeight = 2 * this.radiusY;

		} else if (ORYX.Editor.checkClassType(this.element, SVGLineElement)) {
			this.type = "Line";

			var x1 = undefined;
			var y1 = undefined;
			var x2 = undefined;
			var y2 = undefined;
			var x1Attr = this.element.getAttributeNS(null, "x1");
			if (x1Attr) {
				x1 = parseFloat(x1Attr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var y1Attr = this.element.getAttributeNS(null, "y1");
			if (y1Attr) {
				y1 = parseFloat(y1Attr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var x2Attr = this.element.getAttributeNS(null, "x2");
			if (x2Attr) {
				x2 = parseFloat(x2Attr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			var y2Attr = this.element.getAttributeNS(null, "y2");
			if (y2Attr) {
				y2 = parseFloat(y2Attr);
			} else {
				throw "Missing attribute in element " + this.element;
			}
			this.oldX = Math.min(x1, x2);
			this.oldY = Math.min(y1, y2);
			this.oldWidth = Math.abs(x1 - x2);
			this.oldHeight = Math.abs(y1 - y2);

		} else if (ORYX.Editor.checkClassType(this.element, SVGPolylineElement)
				|| ORYX.Editor.checkClassType(this.element, SVGPolygonElement)) {
			this.type = "Polyline";

			var pointsArray = [];
			if (this.element.points && this.element.points.numberOfItems) {
				for (var i = 0, size = this.element.points.numberOfItems; i < size; i++) {
					pointsArray.push(this.element.points.getItem(i).x)
					pointsArray.push(this.element.points.getItem(i).y)
				}
			} else {
				var points = this.element.getAttributeNS(null, "points");
				if (points) {
					points = points.replace(/,/g, " ");
					pointsArray = points.split(" ");
					pointsArray = pointsArray.without("");
				} else {
					throw "Missing attribute in element " + this.element;
				}
			}

			if (pointsArray && pointsArray.length && pointsArray.length > 1) {
				var minX = parseFloat(pointsArray[0]);
				var minY = parseFloat(pointsArray[1]);
				var maxX = parseFloat(pointsArray[0]);
				var maxY = parseFloat(pointsArray[1]);

				for (var i = 0; i < pointsArray.length; i++) {
					minX = Math.min(minX, parseFloat(pointsArray[i]));
					maxX = Math.max(maxX, parseFloat(pointsArray[i]));
					i++;
					minY = Math.min(minY, parseFloat(pointsArray[i]));
					maxY = Math.max(maxY, parseFloat(pointsArray[i]));
				}

				this.oldX = minX;
				this.oldY = minY;
				this.oldWidth = maxX - minX;
				this.oldHeight = maxY - minY;
			} else {
				throw "Missing attribute in element " + this.element;
			}

		} else if (ORYX.Editor.checkClassType(this.element, SVGPathElement)) {
			this.type = "Path";

			this.editPathParser = new PathParser();
			this.editPathHandler = new ORYX.Core.SVG.EditPathHandler();
			this.editPathParser.setHandler(this.editPathHandler);

			var parser = new PathParser();
			var handler = new ORYX.Core.SVG.MinMaxPathHandler();
			parser.setHandler(handler);
			parser.parsePath(this.element);

			this.oldX = handler.minX;
			this.oldY = handler.minY;
			this.oldWidth = handler.maxX - handler.minX;
			this.oldHeight = handler.maxY - handler.minY;

			delete parser;
			delete handler;
		} else {
			throw "Element is not a shape.";
		}

		/** initialize attributes of oryx namespace */
		// resize
		var resizeAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resize");
		if (resizeAttr) {
			resizeAttr = resizeAttr.toLowerCase();
			if (resizeAttr.match(/horizontal/)) {
				this.isHorizontallyResizable = true;
			} else {
				this.isHorizontallyResizable = false;
			}
			if (resizeAttr.match(/vertical/)) {
				this.isVerticallyResizable = true;
			} else {
				this.isVerticallyResizable = false;
			}
		} else {
			this.isHorizontallyResizable = false;
			this.isVerticallyResizable = false;
		}

		// anchors
		var anchorAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "anchors");
		if (anchorAttr) {
			anchorAttr = anchorAttr.replace("/,/g", " ");
			var anchors = anchorAttr.split(" ").without("");

			for (var i = 0; i < anchors.length; i++) {
				switch (anchors[i].toLowerCase()) {
					case "left" :
						this.anchorLeft = true;
						break;
					case "right" :
						this.anchorRight = true;
						break;
					case "top" :
						this.anchorTop = true;
						break;
					case "bottom" :
						this.anchorBottom = true;
						break;
				}
			}
		}

		// allowDockers and resizeMarkerMid
		if (ORYX.Editor.checkClassType(this.element, SVGPathElement)) {
			var allowDockersAttr = this.element.getAttributeNS(NAMESPACE_ORYX,
					"allowDockers");
			if (allowDockersAttr) {
				if (allowDockersAttr.toLowerCase() === "no") {
					this.allowDockers = false;
				} else {
					this.allowDockers = true;
				}
			}

			var resizeMarkerMidAttr = this.element.getAttributeNS(
					NAMESPACE_ORYX, "resizeMarker-mid");
			if (resizeMarkerMidAttr) {
				if (resizeMarkerMidAttr.toLowerCase() === "yes") {
					this.resizeMarkerMid = true;
				} else {
					this.resizeMarkerMid = false;
				}
			}
		}

		this.x = this.oldX;
		this.y = this.oldY;
		this.width = this.oldWidth;
		this.height = this.oldHeight;
	},

	/**
	 * Writes the changed values into the SVG element.
	 */
	update : function() {

		if (this.x !== this.oldX || this.y !== this.oldY
				|| this.width !== this.oldWidth
				|| this.height !== this.oldHeight) {
			switch (this.type) {
				case "Rect" :
					if (this.x !== this.oldX)
						this.element.setAttributeNS(null, "x", this.x);
					if (this.y !== this.oldY)
						this.element.setAttributeNS(null, "y", this.y);
					if (this.width !== this.oldWidth)
						this.element.setAttributeNS(null, "width", this.width);
					if (this.height !== this.oldHeight)
						this.element
								.setAttributeNS(null, "height", this.height);
					break;
				case "Circle" :
					// calculate the radius
					// var r;
					// if(this.width/this.oldWidth <=
					// this.height/this.oldHeight) {
					// this.radiusX = ((this.width > this.height) ? this.width :
					// this.height)/2.0;
					// } else {
					this.radiusX = ((this.width < this.height)
							? this.width
							: this.height)
							/ 2.0;
					// }

					this.element.setAttributeNS(null, "cx", this.x + this.width
									/ 2.0);
					this.element.setAttributeNS(null, "cy", this.y
									+ this.height / 2.0);
					this.element.setAttributeNS(null, "r", this.radiusX);
					break;
				case "Ellipse" :
					this.radiusX = this.width / 2;
					this.radiusY = this.height / 2;

					this.element.setAttributeNS(null, "cx", this.x
									+ this.radiusX);
					this.element.setAttributeNS(null, "cy", this.y
									+ this.radiusY);
					this.element.setAttributeNS(null, "rx", this.radiusX);
					this.element.setAttributeNS(null, "ry", this.radiusY);
					break;
				case "Line" :
					if (this.x !== this.oldX)
						this.element.setAttributeNS(null, "x1", this.x);

					if (this.y !== this.oldY)
						this.element.setAttributeNS(null, "y1", this.y);

					if (this.x !== this.oldX || this.width !== this.oldWidth)
						this.element.setAttributeNS(null, "x2", this.x
										+ this.width);

					if (this.y !== this.oldY || this.height !== this.oldHeight)
						this.element.setAttributeNS(null, "y2", this.y
										+ this.height);
					break;
				case "Polyline" :
					var points = this.element.getAttributeNS(null, "points");
					if (points) {
						points = points.replace(/,/g, " ").split(" ")
								.without("");

						if (points && points.length && points.length > 1) {

							// TODO what if oldWidth == 0?
							var widthDelta = (this.oldWidth === 0)
									? 0
									: this.width / this.oldWidth;
							var heightDelta = (this.oldHeight === 0)
									? 0
									: this.height / this.oldHeight;

							var updatedPoints = "";
							for (var i = 0; i < points.length; i++) {
								var x = (parseFloat(points[i]) - this.oldX)
										* widthDelta + this.x;
								i++;
								var y = (parseFloat(points[i]) - this.oldY)
										* heightDelta + this.y;
								updatedPoints += x + " " + y + " ";
							}
							this.element.setAttributeNS(null, "points",
									updatedPoints);
						} else {
							// TODO error
						}
					} else {
						// TODO error
					}
					break;
				case "Path" :
					// calculate scaling delta
					// TODO what if oldWidth == 0?
					var widthDelta = (this.oldWidth === 0) ? 0 : this.width
							/ this.oldWidth;
					var heightDelta = (this.oldHeight === 0) ? 0 : this.height
							/ this.oldHeight;

					// use path parser to edit each point of the path
					this.editPathHandler.init(this.x, this.y, this.oldX,
							this.oldY, widthDelta, heightDelta);
					this.editPathParser.parsePath(this.element);

					// change d attribute of path
					this.element.setAttributeNS(null, "d",
							this.editPathHandler.d);
					break;
			}

			this.oldX = this.x;
			this.oldY = this.y;
			this.oldWidth = this.width;
			this.oldHeight = this.height;
		}

		// Remove cached variables
		delete this.visible;
		delete this.handler;
	},

	isPointIncluded : function(pointX, pointY) {

		// Check if there are the right arguments and if the node is visible
		if (!pointX || !pointY || !this.isVisible()) {
			return false;
		}

		switch (this.type) {
			case "Rect" :
				return (pointX >= this.x && pointX <= this.x + this.width
						&& pointY >= this.y && pointY <= this.y + this.height);
				break;
			case "Circle" :
				// calculate the radius
				// var r;
				// if(this.width/this.oldWidth <= this.height/this.oldHeight) {
				// r = ((this.width > this.height) ? this.width :
				// this.height)/2.0;
				// } else {
				// r = ((this.width < this.height) ? this.width :
				// this.height)/2.0;
				// }
				return ORYX.Core.Math.isPointInEllipse(pointX, pointY, this.x
								+ this.width / 2.0, this.y + this.height / 2.0,
						this.radiusX, this.radiusX);
				break;
			case "Ellipse" :
				return ORYX.Core.Math.isPointInEllipse(pointX, pointY, this.x
								+ this.radiusX, this.y + this.radiusY,
						this.radiusX, this.radiusY);
				break;
			case "Line" :
				return ORYX.Core.Math.isPointInLine(pointX, pointY, this.x,
						this.y, this.x + this.width, this.y + this.height);
				break;
			case "Polyline" :
				var points = this.element.getAttributeNS(null, "points");

				if (points) {
					points = points.replace(/,/g, " ").split(" ").without("");

					points = points.collect(function(n) {
								return parseFloat(n);
							});

					return ORYX.Core.Math.isPointInPolygone(pointX, pointY,
							points);
				} else {
					return false;
				}
				break;
			case "Path" :

				// Cache Path handler
				if (!this.handler) {
					var parser = new PathParser();
					this.handler = new ORYX.Core.SVG.PointsPathHandler();
					parser.setHandler(this.handler);
					parser.parsePath(this.element);
				}

				return ORYX.Core.Math.isPointInPolygone(pointX, pointY,
						this.handler.points);

				break;
			default :
				return false;
		}
	},

	/**
	 * Returns true if the element is visible
	 * 
	 * @param {SVGElement}
	 *            elem
	 * @return boolean
	 */
	isVisible : function(elem) {

		if (this.visible !== undefined) {
			return this.visible;
		}

		if (!elem) {
			elem = this.element;
		}

		var hasOwnerSVG = false;
		try {
			hasOwnerSVG = !!elem.ownerSVGElement;
		} catch (e) {
		}

		// Is SVG context
		if (hasOwnerSVG) {
			// IF G-Element
			if (ORYX.Editor.checkClassType(elem, SVGGElement)) {
				if (elem.className && elem.className.baseVal == "me") {
					this.visible = true;
					return this.visible;
				}
			}

			// Check if fill or stroke is set
			var fill = elem.getAttributeNS(null, "fill");
			var stroke = elem.getAttributeNS(null, "stroke");
			if (fill && fill == "none" && stroke && stroke == "none") {
				this.visible = false;
			} else {
				// Check if displayed
				var attr = elem.getAttributeNS(null, "display");
				if (!attr)
					this.visible = this.isVisible(elem.parentNode);
				else if (attr == "none")
					this.visible = false;
				else
					this.visible = true;
			}
		} else {
			this.visible = true;
		}

		return this.visible;
	},

	toString : function() {
		return (this.element) ? "SVGShape " + this.element.id : "SVGShape "
				+ this.element;
	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.SVG) {
	ORYX.Core.SVG = {};
}

/**
 * @classDescription Class for adding text to a shape.
 * 
 */
ORYX.Core.SVG.Label = Clazz.extend({

	_characterSets : ["%W", "@", "m", "wDGMOQ?????#+=<>~^",
			"ABCHKNRSUVXZ??????????&",
			"bdghnopqux???????????ETY1234567890?????_????${}*????`???????????",
			"aeksvyz?????FLP????????????????", "c-", "rtJ\"/()[]:;!|\\",
			"fjI., ", "'", "il"],
	_characterSetValues : [15, 14, 13, 11, 10, 9, 8, 7, 6, 5, 4, 3],

	/**
	 * Constructor
	 * 
	 * @param options
	 *            {Object} : textElement
	 * 
	 */
	construct : function(options) {
		arguments.callee.$.construct.apply(this, arguments);

		if (!options.textElement) {
			throw "Label: No parameter textElement."
		} else if (!ORYX.Editor.checkClassType(options.textElement,
				SVGTextElement)) {
			throw "Label: Parameter textElement is not an SVGTextElement."
		}

		this.invisibleRenderPoint = -5000;

		this.node = options.textElement;

		this.node.setAttributeNS(null, 'stroke-width', '0pt');
		this.node.setAttributeNS(null, 'letter-spacing', '-0.01px');

		this.shapeId = options.shapeId;

		this.id;

		this.fitToElemId;

		this.edgePosition;

		this.x;
		this.y;
		this.oldX;
		this.oldY;

		this.isVisible = true;

		this._text;
		this._verticalAlign;
		this._horizontalAlign;
		this._rotate;
		this._rotationPoint;

		// this.anchors = [];
		this.anchorLeft;
		this.anchorRight;
		this.anchorTop;
		this.anchorBottom;

		this._isChanged = true;

		// if the text element already has an id, don't change it.
		var _id = this.node.getAttributeNS(null, 'id');
		if (_id) {
			this.id = _id;
		}

		// initialization

		// set referenced element the text is fit to
		this.fitToElemId = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX,
				'fittoelem');
		if (this.fitToElemId)
			this.fitToElemId = this.shapeId + this.fitToElemId;

		// set alignment
		var alignValues = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX,
				'align');
		if (alignValues) {
			alignValues = alignValues.replace(/,/g, " ");
			alignValues = alignValues.split(" ");
			alignValues = alignValues.without("");

			alignValues.each((function(alignValue) {
				switch (alignValue) {
					case 'top' :
					case 'middle' :
					case 'bottom' :
						if (!this._verticalAlign) {
							this._originVerticalAlign = this._verticalAlign = alignValue;
						}
						break;
					case 'left' :
					case 'center' :
					case 'right' :
						if (!this._horizontalAlign) {
							this._originHorizontalAlign = this._horizontalAlign = alignValue;
						}
						break;
				}
			}).bind(this));
		}

		// set edge position (only in case the label belongs to an edge)
		this.edgePosition = this.node.getAttributeNS(
				ORYX.CONFIG.NAMESPACE_ORYX, 'edgePosition');
		if (this.edgePosition) {
			this.originEdgePosition = this.edgePosition = this.edgePosition
					.toLowerCase();
		}

		// get offset top
		this.offsetTop = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX,
				'offsetTop')
				|| ORYX.CONFIG.OFFSET_EDGE_LABEL_TOP;
		if (this.offsetTop) {
			this.offsetTop = parseInt(this.offsetTop);
		}

		// get offset top
		this.offsetBottom = this.node.getAttributeNS(
				ORYX.CONFIG.NAMESPACE_ORYX, 'offsetBottom')
				|| ORYX.CONFIG.OFFSET_EDGE_LABEL_BOTTOM;
		if (this.offsetBottom) {
			this.offsetBottom = parseInt(this.offsetBottom);
		}

		// set rotation
		var rotateValue = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX,
				'rotate');
		if (rotateValue) {
			try {
				this._rotate = parseFloat(rotateValue);
			} catch (e) {
				this._rotate = 0;
			}
		} else {
			this._rotate = 0;
		}

		// anchors
		var anchorAttr = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX,
				"anchors");
		if (anchorAttr) {
			anchorAttr = anchorAttr.replace("/,/g", " ");
			var anchors = anchorAttr.split(" ").without("");

			for (var i = 0; i < anchors.length; i++) {
				switch (anchors[i].toLowerCase()) {
					case "left" :
						this.originAnchorLeft = this.anchorLeft = true;
						break;
					case "right" :
						this.originAnchorRight = this.anchorRight = true;
						break;
					case "top" :
						this.originAnchorTop = this.anchorTop = true;
						break;
					case "bottom" :
						this.originAnchorBottom = this.anchorBottom = true;
						break;
				}
			}
		}

		// if no alignment defined, set default alignment
		if (!this._verticalAlign) {
			this._verticalAlign = 'bottom';
		}
		if (!this._horizontalAlign) {
			this._horizontalAlign = 'left';
		}

		var xValue = this.node.getAttributeNS(null, 'x');
		if (xValue) {
			this.oldX = this.x = parseFloat(xValue);
		} else {
			// TODO error
		}

		var yValue = this.node.getAttributeNS(null, 'y');
		if (yValue) {
			this.oldY = this.y = parseFloat(yValue);
		} else {
			// TODO error
		}

		// set initial text
		this.text(this.node.textContent);
	},

	/**
	 * Reset the anchor position to the original value which was specified in
	 * the stencil set
	 * 
	 */
	resetAnchorPosition : function() {
		this.anchorLeft = this.originAnchorLeft || false;
		this.anchorRight = this.originAnchorRight || false;
		this.anchorTop = this.originAnchorTop || false;
		this.anchorBottom = this.originAnchorBottom || false;
	},

	isOriginAnchorLeft : function() {
		return this.originAnchorLeft || false;
	},
	isOriginAnchorRight : function() {
		return this.originAnchorRight || false;
	},
	isOriginAnchorTop : function() {
		return this.originAnchorTop || false;
	},
	isOriginAnchorBottom : function() {
		return this.originAnchorBottom || false;
	},

	isAnchorLeft : function() {
		return this.anchorLeft || false;
	},
	isAnchorRight : function() {
		return this.anchorRight || false;
	},
	isAnchorTop : function() {
		return this.anchorTop || false;
	},
	isAnchorBottom : function() {
		return this.anchorBottom || false;
	},

	/**
	 * Returns the x coordinate
	 * 
	 * @return {number}
	 */
	getX : function() {
		try {
			var x = this.node.x.baseVal.getItem(0).value;
			switch (this.horizontalAlign()) {
				case "left" :
					return x;
				case "center" :
					return x - (this.getWidth() / 2);
				case "right" :
					return x - this.getWidth();
			}
			return this.node.getBBox().x;
		} catch (e) {
			return this.x;
		}
	},

	setX : function(x) {
		if (this.position)
			this.position.x = x;
		else
			this.setOriginX(x);
	},

	/**
	 * Returns the y coordinate
	 * 
	 * @return {number}
	 */
	getY : function() {
		try {
			return this.node.getBBox().y;
		} catch (e) {
			return this.y;
		}
	},

	setY : function(y) {
		if (this.position)
			this.position.y = y;
		else
			this.setOriginY(y);
	},

	setOriginX : function(x) {
		this.x = x;
	},

	setOriginY : function(y) {
		this.y = y;
	},

	/**
	 * Returns the width of the label
	 * 
	 * @return {number}
	 */
	getWidth : function() {
		try {
			try {
				var width, cn = this.node.childNodes;
				if (cn.length == 0) {
					width = this.node.getBBox().width;
				} else {
					for (var i = 0, size = cn.length; i < size; ++i) {
						var w = cn[i].getComputedTextLength();
						if ("undefined" == typeof width || width < w) {
							width = w;
						}
					}
				}
				return width + (width % 2 == 0 ? 0 : 1);
			} catch (ee) {
				return this.node.getBBox().width;
			}
		} catch (e) {
			return 0;
		}
	},

	getOriginUpperLeft : function() {
		var x = this.x, y = this.y;
		switch (this._horizontalAlign) {
			case 'center' :
				x -= this.getWidth() / 2;
				break;
			case 'right' :
				x -= this.getWidth();
				break;
		}
		switch (this._verticalAlign) {
			case 'middle' :
				y -= this.getHeight() / 2;
				break;
			case 'bottom' :
				y -= this.getHeight();
				break;
		}
		return {
			x : x,
			y : y
		};
	},

	/**
	 * Returns the height of the label
	 * 
	 * @return {number}
	 */
	getHeight : function() {
		try {
			return this.node.getBBox().height;
		} catch (e) {
			return 0;
		}
	},

	/**
	 * Returns the relative center position of the label to its parent shape.
	 * 
	 * @return {Object}
	 */
	getCenter : function() {
		var up = {
			x : this.getX(),
			y : this.getY()
		};
		up.x += this.getWidth() / 2;
		up.y += this.getHeight() / 2;
		return up;
	},

	/**
	 * Sets the position of a label relative to the parent.
	 * 
	 * @param {Object}
	 *            position
	 */
	setPosition : function(position) {
		if (!position || position.x === undefined || position.y === undefined) {
			delete this.position;
		} else {
			this.position = position;
		}

		if (this.position) {
			delete this._referencePoint;
			delete this.edgePosition;
		}

		this._isChanged = true;
		this.update();
	},

	/**
	 * Return the position
	 */
	getPosition : function() {
		return this.position;
	},

	setReferencePoint : function(ref) {
		if (ref) {
			this._referencePoint = ref;
		} else {
			delete this._referencePoint;
		}
		if (this._referencePoint) {
			delete this.position;
		}
	},

	getReferencePoint : function() {
		return this._referencePoint || undefined;
	},

	changed : function() {
		this._isChanged = true;
	},

	/**
	 * Register a callback which will be called if the label was rendered.
	 * 
	 * @param {Object}
	 *            fn
	 */
	registerOnChange : function(fn) {
		if (!this.changeCallbacks) {
			this.changeCallbacks = [];
		}
		if (fn instanceof Function && !this.changeCallbacks.include(fn)) {
			this.changeCallbacks.push(fn);
		}
	},

	/**
	 * Unregister the callback for changes.
	 * 
	 * @param {Object}
	 *            fn
	 */
	unregisterOnChange : function(fn) {
		if (this.changeCallbacks && fn instanceof Function
				&& this.changeCallbacks.include(fn)) {
			this.changeCallbacks = this.changeCallbacks.without(fn);
		}
	},

	/**
	 * Returns TRUE if the labe is currently in the update mechanism.
	 * 
	 * @return {Boolean}
	 */
	isUpdating : function() {
		return !!this._isUpdating;
	},

	getOriginEdgePosition : function() {
		return this.originEdgePosition;
	},

	/**
	 * Returns the edgeposition.
	 * 
	 * @return {String} "starttop", "startmiddle", "startbottom", "midtop",
	 *         "midbottom", "endtop", "endbottom" or null
	 */
	getEdgePosition : function() {
		return this.edgePosition || null;
	},

	/**
	 * Set the edge position, must be one of the valid edge positions (see
	 * getEdgePosition). Removes the reference point and the absolute position
	 * as well.
	 * 
	 * @param {Object}
	 *            position
	 */
	setEdgePosition : function(position) {
		if (["starttop", "startmiddle", "startbottom", "midtop", "midbottom",
				"endtop", "endbottom"].include(position)) {
			this.edgePosition = position;
			delete this.position;
			delete this._referencePoint;
		} else {
			delete this.edgePosition;
		}
	},

	/**
	 * Update the SVG text element.
	 */
	update : function(force) {

		var x = this.x, y = this.y;
		if (this.position) {
			x = this.position.x;
			y = this.position.y;
		}
		x = Math.floor(x);
		y = Math.floor(y);

		if (this._isChanged || x !== this.oldX || y !== this.oldY
				|| force === true) {
			if (this.isVisible) {
				this._isChanged = false;
				this._isUpdating = true;

				this.node.setAttributeNS(null, 'x', x);
				this.node.setAttributeNS(null, 'y', y);
				this.node.removeAttributeNS(null, "fill-opacity");

				// this.node.setAttributeNS(null, 'font-size', this._fontSize);
				// this.node.setAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'align',
				// this._horizontalAlign + " " + this._verticalAlign);

				this.oldX = x;
				this.oldY = y;

				// set rotation
				if (!this.position && !this.getReferencePoint()) {
					if (this._rotate !== undefined) {
						if (this._rotationPoint)
							this.node.setAttributeNS(null, 'transform',
									'rotate(' + this._rotate + ' '
											+ Math.floor(this._rotationPoint.x)
											+ ' '
											+ Math.floor(this._rotationPoint.y)
											+ ')');
						else
							this.node.setAttributeNS(null, 'transform',
									'rotate(' + this._rotate + ' '
											+ Math.floor(x) + ' '
											+ Math.floor(y) + ')');
					}
				} else {
					this.node.removeAttributeNS(null, 'transform');
				}

				var textLines = this._text.split("\n");
				while (textLines.last() == "")
					textLines.pop();

				if (this.node.ownerDocument) {
					// Only reset the tspans if the text
					// has changed or has to be wrapped
					if (this.fitToElemId || this._textHasChanged) {
						this.node.textContent = ""; // Remove content
						textLines.each((function(textLine, index) {
									var tspan = this.node.ownerDocument
											.createElementNS(
													ORYX.CONFIG.NAMESPACE_SVG,
													'tspan');
									tspan.textContent = textLine.trim();
									if (this.fitToElemId) {
										tspan.setAttributeNS(null, 'x',
												this.invisibleRenderPoint);
										tspan.setAttributeNS(null, 'y',
												this.invisibleRenderPoint);
									}

									/*
									 * Chrome's getBBox() method fails, if a
									 * text node contains an empty tspan
									 * element. So, we add a whitespace to such
									 * a tspan element.
									 */
									if (tspan.textContent === "") {
										tspan.textContent = " ";
									}

									// append tspan to text node
									this.node.appendChild(tspan);
								}).bind(this));
						delete this._textHasChanged;
						delete this.indices;
					}

					// Work around for Mozilla bug 293581
					if (this.isVisible && this.fitToElemId) {
						this.node.setAttributeNS(null, 'visibility', 'hidden');
					}

					if (this.fitToElemId) {
						window.setTimeout(this._checkFittingToReferencedElem
										.bind(this), 0);
						// this._checkFittingToReferencedElem();
					} else {
						window.setTimeout(this._positionText.bind(this), 0);
						// this._positionText();
					}
				}
			} else {
				this.node.textContent = "";
				// this.node.setAttributeNS(null, "fill-opacity", "0.2");
			}
		}
	},

	_checkFittingToReferencedElem : function() {
		try {
			var tspans = $A(this.node.getElementsByTagNameNS(
					ORYX.CONFIG.NAMESPACE_SVG, 'tspan'));

			// only do this in firefox 3. all other browsers do not support word
			// wrapping!!!!!
			// if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new
			// Number(RegExp.$1)>=3) {
			var newtspans = [];

			var refNode = this.node.ownerDocument
					.getElementById(this.fitToElemId);

			if (refNode) {
				var refbb = refNode.getBBox();

				var fontSize = this.getFontSize();

				for (var j = 0; j < tspans.length; j++) {
					var tspan = tspans[j];

					var textLength = this._getRenderedTextLength(tspan,
							undefined, undefined, fontSize);

					var refBoxLength = (this._rotate != 0
							&& this._rotate % 180 != 0
							&& this._rotate % 90 == 0
							? refbb.height
							: refbb.width);

					if (textLength > refBoxLength) {

						var startIndex = 0;
						var lastSeperatorIndex = 0;

						var numOfChars = this
								.getTrimmedTextLength(tspan.textContent);
						for (var i = 0; i < numOfChars; i++) {
							var sslength = this._getRenderedTextLength(tspan,
									startIndex, i - startIndex, fontSize);

							if (sslength > refBoxLength - 2) {
								var newtspan = this.node.ownerDocument
										.createElementNS(
												ORYX.CONFIG.NAMESPACE_SVG,
												'tspan');
								if (lastSeperatorIndex <= startIndex) {
									lastSeperatorIndex = (i == 0) ? i : i - 1;
									newtspan.textContent = tspan.textContent
											.slice(startIndex,
													lastSeperatorIndex).trim();
									// lastSeperatorIndex = i;
								} else {
									newtspan.textContent = tspan.textContent
											.slice(startIndex,
													++lastSeperatorIndex)
											.trim();
								}

								newtspan.setAttributeNS(null, 'x',
										this.invisibleRenderPoint);
								newtspan.setAttributeNS(null, 'y',
										this.invisibleRenderPoint);

								// insert tspan to text node
								// this.node.insertBefore(newtspan, tspan);
								newtspans.push(newtspan);

								startIndex = lastSeperatorIndex;
							} else {
								var curChar = tspan.textContent.charAt(i);
								if (curChar == ' ' || curChar == '-'
										|| curChar == "." || curChar == ","
										|| curChar == ";" || curChar == ":") {
									lastSeperatorIndex = i;
								}
							}
						}

						tspan.textContent = tspan.textContent.slice(startIndex)
								.trim();
					}

					newtspans.push(tspan);
				}

				while (this.node.hasChildNodes())
					this.node.removeChild(this.node.childNodes[0]);

				while (newtspans.length > 0) {
					this.node.appendChild(newtspans.shift());
				}
			}
			// }
		} catch (e) {
			ORYX.Log.fatal("Error " + e);
		}
		window.setTimeout(this._positionText.bind(this), 0);
		// this._positionText();
	},

	/**
	 * This is a work around method for Mozilla bug 293581. Before the method
	 * getComputedTextLength works, the text has to be rendered.
	 */
	_positionText : function() {
		try {

			var tspans = this.node.childNodes;

			var fontSize = this.getFontSize(this.node);

			var invalidTSpans = [];

			var x = this.x, y = this.y;
			if (this.position) {
				x = this.position.x;
				y = this.position.y;
			}
			x = Math.floor(x);
			y = Math.floor(y);

			var i = 0, indic = []; // Cache indices if the _positionText is
									// called again, before update is called
			var is = (this.indices || $R(0, tspans.length - 1).toArray());
			var length = is.length;
			is.each((function(index) {
						if ("undefined" == typeof index) {
							return;
						}

						var tspan = tspans[i++];

						if (tspan.textContent.trim() === "") {
							invalidTSpans.push(tspan);
						} else {
							// set vertical position
							var dy = 0;
							switch (this._verticalAlign) {
								case 'bottom' :
									dy = -(length - index - 1) * (fontSize);
									break;
								case 'middle' :
									dy = -(length / 2.0 - index - 1)
											* (fontSize);
									dy -= ORYX.CONFIG.LABEL_LINE_DISTANCE / 2;
									break;
								case 'top' :
									dy = index * (fontSize);
									dy += fontSize;
									break;
							}
							tspan.setAttributeNS(null, 'dy', Math.floor(dy));

							tspan.setAttributeNS(null, 'x', x);
							tspan.setAttributeNS(null, 'y', y);
							indic.push(index);
						}

					}).bind(this));

			indic.length = tspans.length;
			this.indices = this.indices || indic;

			invalidTSpans.each(function(tspan) {
						this.node.removeChild(tspan)
					}.bind(this));

			// set horizontal alignment
			switch (this._horizontalAlign) {
				case 'left' :
					this.node.setAttributeNS(null, 'text-anchor', 'start');
					break;
				case 'center' :
					this.node.setAttributeNS(null, 'text-anchor', 'middle');
					break;
				case 'right' :
					this.node.setAttributeNS(null, 'text-anchor', 'end');
					break;
			}

		} catch (e) {
			// console.log(e);
			this._isChanged = true;
		}

		if (this.isVisible) {
			this.node.removeAttributeNS(null, 'visibility');
		}

		// Finished
		delete this._isUpdating;

		// Raise change event
		(this.changeCallbacks || []).each(function(fn) {
					fn.apply(fn);
				})

	},

	/**
	 * Returns the text length of the text content of an SVG tspan element. For
	 * all browsers but Firefox 3 the values are estimated.
	 * 
	 * @param {TSpanSVGElement}
	 *            tspan
	 * @param {int}
	 *            startIndex Optional, for sub strings
	 * @param {int}
	 *            endIndex Optional, for sub strings
	 */
	_getRenderedTextLength : function(tspan, startIndex, endIndex, fontSize) {
		// if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new
		// Number(RegExp.$1) >= 3) {
		if (startIndex === undefined) {
			// test string: abcdefghijklmnopqrstuvwxyz????????????????,.-#+
			// 1234567890?????ABCDEFGHIJKLMNOPQRSTUVWXYZ;:_'*???????????????!"????$%&/()=?[]{}|<>'~????`\^?????????@?????????????????
			// for(var i = 0; i < tspan.textContent.length; i++) {
			// console.log(tspan.textContent.charAt(i),
			// tspan.getSubStringLength(i,1),
			// this._estimateCharacterWidth(tspan.textContent.charAt(i))*(fontSize/14.0));
			// }
			return tspan.getComputedTextLength();
		} else {
			return tspan.getSubStringLength(startIndex, endIndex);
		}
		/*
		 * } else { if(startIndex === undefined) { return
		 * this._estimateTextWidth(tspan.textContent, fontSize); } else { return
		 * this._estimateTextWidth(tspan.textContent.substr(startIndex,
		 * endIndex).trim(), fontSize); } }
		 */
	},

	/**
	 * Estimates the text width for a string. Used for word wrapping in all
	 * browser but FF3.
	 * 
	 * @param {Object}
	 *            text
	 */
	_estimateTextWidth : function(text, fontSize) {
		var sum = 0.0;
		for (var i = 0; i < text.length; i++) {
			sum += this._estimateCharacterWidth(text.charAt(i));
		}

		return sum * (fontSize / 14.0);
	},

	/**
	 * Estimates the width of a single character for font size 14. Used for word
	 * wrapping in all browser but FF3.
	 * 
	 * @param {Object}
	 *            character
	 */
	_estimateCharacterWidth : function(character) {
		for (var i = 0; i < this._characterSets.length; i++) {
			if (this._characterSets[i].indexOf(character) >= 0) {
				return this._characterSetValues[i];
			}
		}
		return 9;
	},

	getReferencedElementWidth : function() {
		var refNode = this.node.ownerDocument.getElementById(this.fitToElemId);

		if (refNode) {
			var refbb = refNode.getBBox();

			if (refbb) {
				return (this._rotate != 0 && this._rotate % 180 != 0
						&& this._rotate % 90 == 0 ? refbb.height : refbb.width);
			}
		}

		return undefined;
	},

	/**
	 * If no parameter is provided, this method returns the current text.
	 * 
	 * @param text
	 *            {String} Optional. Replaces the old text with this one.
	 */
	text : function() {
		switch (arguments.length) {
			case 0 :
				return this._text
				break;

			case 1 :
				var oldText = this._text;
				if (arguments[0]) {
					// Filter out multiple spaces to fix issue in chrome for
					// line-wrapping
					this._text = arguments[0].toString();
					if (this._text != null && this._text != undefined) {
						this._text = this._text.replace(/ {2,}/g, ' ');
					}
				} else {
					this._text = "";
				}
				if (oldText !== this._text) {
					this._isChanged = true;
					this._textHasChanged = true;
				}
				break;

			default :
				// TODO error
				break;
		}
	},

	getOriginVerticalAlign : function() {
		return this._originVerticalAlign;
	},

	verticalAlign : function() {
		switch (arguments.length) {
			case 0 :
				return this._verticalAlign;
			case 1 :
				if (['top', 'middle', 'bottom'].member(arguments[0])) {
					var oldValue = this._verticalAlign;
					this._verticalAlign = arguments[0];
					if (this._verticalAlign !== oldValue) {
						this._isChanged = true;
					}
				}
				break;

			default :
				// TODO error
				break;
		}
	},

	getOriginHorizontalAlign : function() {
		return this._originHorizontalAlign;
	},

	horizontalAlign : function() {
		switch (arguments.length) {
			case 0 :
				return this._horizontalAlign;
			case 1 :
				if (['left', 'center', 'right'].member(arguments[0])) {
					var oldValue = this._horizontalAlign;
					this._horizontalAlign = arguments[0];
					if (this._horizontalAlign !== oldValue) {
						this._isChanged = true;
					}
				}
				break;

			default :
				// TODO error
				break;
		}
	},

	rotate : function() {
		switch (arguments.length) {
			case 0 :
				return this._rotate;
			case 1 :
				if (this._rotate != arguments[0]) {
					this._rotate = arguments[0];
					this._rotationPoint = undefined;
					this._isChanged = true;
				}
			case 2 :
				if (this._rotate != arguments[0] || !this._rotationPoint
						|| this._rotationPoint.x != arguments[1].x
						|| this._rotationPoint.y != arguments[1].y) {
					this._rotate = arguments[0];
					this._rotationPoint = arguments[1];
					this._isChanged = true;
				}

		}
	},

	hide : function() {
		if (this.isVisible) {
			this.isVisible = false;
			this._isChanged = true;
		}
	},

	show : function() {
		if (!this.isVisible) {
			this.isVisible = true;
			this._isChanged = true;

			// Since text is removed from the tspan when "hidden", mark
			// the text as changed to get it redrawn
			this._textHasChanged = true;
		}
	},

	/**
	 * iterates parent nodes till it finds a SVG font-size attribute.
	 * 
	 * @param {SVGElement}
	 *            node
	 */
	getInheritedFontSize : function(node) {
		if (!node || !node.getAttributeNS)
			return;

		var attr = node.getAttributeNS(null, "font-size");
		if (attr) {
			return parseFloat(attr);
		} else if (!ORYX.Editor.checkClassType(node, SVGSVGElement)) {
			return this.getInheritedFontSize(node.parentNode);
		}
	},

	getFontSize : function(node) {
		var tspans = this.node.getElementsByTagNameNS(
				ORYX.CONFIG.NAMESPACE_SVG, 'tspan');

		// trying to get an inherited font-size attribute
		// NO CSS CONSIDERED!
		var fontSize = this.getInheritedFontSize(this.node);

		if (!fontSize) {
			// because this only works in firefox 3, all other browser use the
			// default line height
			if (tspans[0]
					&& /Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)
					&& new Number(RegExp.$1) >= 3) {
				fontSize = tspans[0].getExtentOfChar(0).height;
			} else {
				fontSize = ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT;
			}

			// handling of unsupported method in webkit
			if (fontSize <= 0) {
				fontSize = ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT;
			}
		}

		if (fontSize)
			this.node.setAttribute("oryx:fontSize", fontSize);

		return fontSize;
	},

	/**
	 * Get trimmed text length for use with getExtentOfChar and
	 * getSubStringLength.
	 * 
	 * @param {String}
	 *            text
	 */
	getTrimmedTextLength : function(text) {
		text = text.strip().gsub('  ', ' ');

		var oldLength;
		do {
			oldLength = text.length;
			text = text.gsub('  ', ' ');
		} while (oldLength > text.length);

		return text.length;
	},

	/**
	 * Returns the offset from edge to the label which is positioned under the
	 * edge
	 * 
	 * @return {int}
	 */
	getOffsetBottom : function() {
		return this.offsetBottom;
	},

	/**
	 * Returns the offset from edge to the label which is positioned over the
	 * edge
	 * 
	 * @return {int}
	 */
	getOffsetTop : function() {
		return this.offsetTop;
	},

	/**
	 * 
	 * @param {Object}
	 *            obj
	 */
	deserialize : function(obj, shape) {
		if (obj && "undefined" != typeof obj.x && "undefined" != typeof obj.y) {
			this.setPosition({
						x : obj.x,
						y : obj.y
					});

			if ("undefined" != typeof obj.distance) {
				var from = shape.dockers[obj.from];
				var to = shape.dockers[obj.to];
				if (from && to) {
					this.setReferencePoint({
								dirty : true,
								distance : obj.distance,
								intersection : {
									x : obj.x,
									y : obj.y
								},
								orientation : obj.orientation,
								segment : {
									from : from,
									fromIndex : obj.from,
									fromPosition : from.bounds.center(),
									to : to,
									toIndex : obj.to,
									toPosition : to.bounds.center()
								}
							})
				}
			}

			if (obj.left)
				this.anchorLeft = true;
			if (obj.right)
				this.anchorRight = true;
			if (obj.top)
				this.anchorTop = true;
			if (obj.bottom)
				this.anchorBottom = true;
			if (obj.valign)
				this.verticalAlign(obj.valign);
			if (obj.align)
				this.horizontalAlign(obj.align);

		} else if (obj && "undefined" != typeof obj.edge) {
			this.setEdgePosition(obj.edge);
		}
	},

	/**
	 * 
	 * @return {Object}
	 */
	serialize : function() {

		// On edge position
		if (this.getEdgePosition()) {
			if (this.getOriginEdgePosition() !== this.getEdgePosition()) {
				return {
					edge : this.getEdgePosition()
				};
			} else {
				return null;
			}
		}

		// On self defined position
		if (this.position) {
			var pos = {
				x : this.position.x,
				y : this.position.y
			};
			if (this.isAnchorLeft()
					&& this.isAnchorLeft() !== this.isOriginAnchorLeft()) {
				pos.left = true;
			}
			if (this.isAnchorRight()
					&& this.isAnchorRight() !== this.isOriginAnchorRight()) {
				pos.right = true;
			}
			if (this.isAnchorTop()
					&& this.isAnchorTop() !== this.isOriginAnchorTop()) {
				pos.top = true;
			}
			if (this.isAnchorBottom()
					&& this.isAnchorBottom() !== this.isOriginAnchorBottom()) {
				pos.bottom = true;
			}

			if (this.getOriginVerticalAlign() !== this.verticalAlign()) {
				pos.valign = this.verticalAlign();
			}
			if (this.getOriginHorizontalAlign() !== this.horizontalAlign()) {
				pos.align = this.horizontalAlign();
			}

			return pos;
		}

		// On reference point which is interesting for edges
		if (this.getReferencePoint()) {
			var ref = this.getReferencePoint();
			return {
				distance : ref.distance,
				x : ref.intersection.x,
				y : ref.intersection.y,
				from : ref.segment.fromIndex,
				to : ref.segment.toIndex,
				orientation : ref.orientation,
				valign : this.verticalAlign(),
				align : this.horizontalAlign()
			}
		}
		return null;
	},

	toString : function() {
		return "Label " + this.id
	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.Math) {
	ORYX.Core.Math = {};
}

/**
 * Calculate the middle point between two given points
 * 
 * @param {x:double,
 *            y:double} point1
 * @param {x:double,
 *            y:double} point2
 * @return the middle point
 */
ORYX.Core.Math.midPoint = function(point1, point2) {
	return {
		x : (point1.x + point2.x) / 2.0,
		y : (point1.y + point2.y) / 2.0
	}
}

/**
 * Returns a TRUE if the point is over a line (defined by point1 and point 2).
 * In Addition a threshold can be set, which defines the weight of those line.
 * 
 * @param {int}
 *            pointX - Point X
 * @param {int}
 *            pointY - Point Y
 * @param {int}
 *            lPoint1X - Line first Point X
 * @param {int}
 *            lPoint1Y - Line first Point Y
 * @param {int}
 *            lPoint2X - Line second Point X
 * @param {int}
 *            lPoint2Y - Line second Point y
 * @param {int}
 *            offset {optional} - maximal distance to line
 * @class ORYX.Core.Math.prototype
 */
ORYX.Core.Math.isPointInLine = function(pointX, pointY, lPoint1X, lPoint1Y,
		lPoint2X, lPoint2Y, offset) {

	offset = offset ? Math.abs(offset) : 1;

	// Check if the edge is vertical
	if (Math.abs(lPoint1X - lPoint2X) <= offset
			&& Math.abs(pointX - lPoint1X) <= offset
			&& pointY - Math.max(lPoint1Y, lPoint2Y) <= offset
			&& Math.min(lPoint1Y, lPoint2Y) - pointY <= offset) {
		return true
	}

	// Check if the edge is horizontal
	if (Math.abs(lPoint1Y - lPoint2Y) <= offset
			&& Math.abs(pointY - lPoint1Y) <= offset
			&& pointX - Math.max(lPoint1X, lPoint2X) <= offset
			&& Math.min(lPoint1X, lPoint2X) - pointX <= offset) {
		return true
	}

	if (pointX > Math.max(lPoint1X, lPoint2X)
			|| pointX < Math.min(lPoint1X, lPoint2X)) {
		return false
	}

	if (pointY > Math.max(lPoint1Y, lPoint2Y)
			|| pointY < Math.min(lPoint1Y, lPoint2Y)) {
		return false
	}

	var s = (lPoint1Y - lPoint2Y) / (lPoint1X - lPoint2X);

	return Math.abs(pointY - ((s * pointX) + lPoint1Y - s * lPoint1X)) < offset
}

/**
 * Get a boolean if the point is in the polygone
 * 
 */
ORYX.Core.Math.isPointInEllipse = function(pointX, pointY, cx, cy, rx, ry) {

	if (cx === undefined || cy === undefined || rx === undefined
			|| ry === undefined) {
		throw "ORYX.Core.Math.isPointInEllipse needs a ellipse with these properties: x, y, radiusX, radiusY"
	}

	var tx = (pointX - cx) / rx;
	var ty = (pointY - cy) / ry;

	return tx * tx + ty * ty < 1.0;
}

/**
 * Get a boolean if the point is in the polygone
 * 
 * @param {int}
 *            pointX
 * @param {int}
 *            pointY
 * @param {[int]}
 *            Cornerpoints of the Polygone (x,y,x,y,...)
 */
ORYX.Core.Math.isPointInPolygone = function(pointX, pointY, polygone) {

	if (arguments.length < 3) {
		throw "ORYX.Core.Math.isPointInPolygone needs two arguments"
	}

	var lastIndex = polygone.length - 1;

	if (polygone[0] !== polygone[lastIndex - 1]
			|| polygone[1] !== polygone[lastIndex]) {
		polygone.push(polygone[0]);
		polygone.push(polygone[1]);
	}

	var crossings = 0;

	var x1, y1, x2, y2, d;

	for (var i = 0; i < polygone.length - 3;) {
		x1 = polygone[i];
		y1 = polygone[++i];
		x2 = polygone[++i];
		y2 = polygone[i + 1];
		d = (pointY - y1) * (x2 - x1) - (pointX - x1) * (y2 - y1);

		if ((y1 >= pointY) != (y2 >= pointY)) {
			crossings += y2 - y1 >= 0 ? d >= 0 : d <= 0;
		}
		if (!d && Math.min(x1, x2) <= pointX && pointX <= Math.max(x1, x2)
				&& Math.min(y1, y2) <= pointY && pointY <= Math.max(y1, y2)) {
			return true;
		}
	}
	return (crossings % 2) ? true : false;
}

/**
 * Calculates the distance between a point and a line. It is also testable, if
 * the distance orthogonal to the line, matches the segment of the line.
 * 
 * @param {float}
 *            lineP1 The starting point of the line segment
 * @param {float}
 *            lineP2 The end point of the line segment
 * @param {Point}
 *            point The point to calculate the distance to.
 * @param {boolean}
 *            toSegmentOnly Flag to signal if only the segment of the line shell
 *            be evaluated.
 */
ORYX.Core.Math.distancePointLinie = function(lineP1, lineP2, point,
		toSegmentOnly) {

	var intersectionPoint = ORYX.Core.Math.getPointOfIntersectionPointLine(
			lineP1, lineP2, point, toSegmentOnly);

	if (!intersectionPoint) {
		return null;
	}

	return ORYX.Core.Math.getDistancePointToPoint(point, intersectionPoint);
};

/**
 * Calculates the distance between two points.
 * 
 * @param {point}
 *            point1
 * @param {point}
 *            point2
 */
ORYX.Core.Math.getDistancePointToPoint = function(point1, point2) {
	return Math.sqrt(Math.pow(point1.x - point2.x, 2)
			+ Math.pow(point1.y - point2.y, 2));
};

/**
 * Calculates the relative distance of a point which is between two other
 * points.
 * 
 * @param {point}
 *            between1
 * @param {point}
 *            between2
 * @param {point}
 *            point
 */
ORYX.Core.Math.getDistanceBetweenTwoPoints = function(between1, between2, point) {
	return ORYX.Core.Math.getDistancePointToPoint(point, between1)
			/ ORYX.Core.Math.getDistancePointToPoint(between1, between2);
};

/**
 * Returns true, if the point is of the left hand side of the regarding the
 * line.
 * 
 * @param {point}
 *            lineP1 Line first point
 * @param {point}
 *            lineP2 Line second point
 * @param {point}
 *            point
 */
ORYX.Core.Math.pointIsLeftOfLine = function(lineP1, lineP2, point) {

	var vec1 = ORYX.Core.Math.getVector(lineP1, lineP2);
	var vec2 = ORYX.Core.Math.getVector(lineP1, point);
	// if the cross produkt is more than 0
	return ((vec1.x * vec2.y) - (vec2.x * vec1.y)) > 0
};

/**
 * Calculates the a point which is relatively between two other points.
 * 
 * @param {point}
 *            point1
 * @param {point}
 *            point2
 * @param {number}
 *            relative Relative which is between 0 and 1
 */
ORYX.Core.Math.getPointBetweenTwoPoints = function(point1, point2, relative) {
	relative = Math.max(Math.min(relative || 0, 1), 0);

	if (relative === 0) {
		return point1;
	} else if (relative === 1) {
		return point2;
	}

	return {
		x : point1.x + ((point2.x - point1.x) * relative),
		y : point1.y + ((point2.y - point1.y) * relative)
	}
};

/**
 * Returns the vector of the both points
 * 
 * @param {point}
 *            point1
 * @param {point}
 *            point2
 */
ORYX.Core.Math.getVector = function(point1, point2) {
	return {
		x : point2.x - point1.x,
		y : point2.y - point1.y
	}
}

/**
 * Returns the an identity vector of the given vector, which has the length ot
 * one.
 * 
 * @param {point}
 *            vector or
 * @param {point}
 *            point1
 * @param {point}
 *            point2
 */
ORYX.Core.Math.getIdentityVector = function(vector) {

	if (arguments.length == 2) {
		vector = ORYX.Core.Math.getVector(arguments[0], arguments[1]);
	}

	var length = Math.sqrt((vector.x * vector.x) + (vector.y * vector.y))
	return {
		x : vector.x / (length || 1),
		y : vector.y / (length || 1)
	}
}

ORYX.Core.Math.getOrthogonalIdentityVector = function(point1, point2) {
	var vec = arguments.length == 1 ? point1 : ORYX.Core.Math
			.getIdentityVector(point1, point2);
	return {
		x : vec.y,
		y : -vec.x
	}
}

/**
 * Returns the intersection point of a line and a point that defines a line
 * orthogonal to the given line.
 * 
 * @param {float}
 *            lineP1 The starting point of the line segment
 * @param {float}
 *            lineP2 The end point of the line segment
 * @param {Point}
 *            point The point to calculate the distance to.
 * @param {boolean}
 *            onSegmentOnly Flag to signal if only the segment of the line shell
 *            be evaluated.
 */
ORYX.Core.Math.getPointOfIntersectionPointLine = function(lineP1, lineP2,
		point, onSegmentOnly) {

	/*
	 * [P3 - P1 - u(P2 - P1)] dot (P2 - P1) = 0 u
	 * =((x3-x1)(x2-x1)+(y3-y1)(y2-y1))/(p2-p1)??
	 */
	var denominator = Math.pow(lineP2.x - lineP1.x, 2)
			+ Math.pow(lineP2.y - lineP1.y, 2);
	if (denominator == 0) {
		return undefined;
	}

	var u = ((point.x - lineP1.x) * (lineP2.x - lineP1.x) + (point.y - lineP1.y)
			* (lineP2.y - lineP1.y))
			/ denominator;

	if (onSegmentOnly) {
		if (!(0 <= u && u <= 1)) {
			return undefined;
		}
	}

	pointOfIntersection = new Object();
	pointOfIntersection.x = lineP1.x + u * (lineP2.x - lineP1.x);
	pointOfIntersection.y = lineP1.y + u * (lineP2.y - lineP1.y);

	return pointOfIntersection;
};

/**
 * Translated the point with the given matrix.
 * 
 * @param {Point}
 *            point
 * @param {Matrix}
 *            matrix
 * @return {Object} Includes x, y
 */
ORYX.Core.Math.getTranslatedPoint = function(point, matrix) {
	var x = matrix.a * point.x + matrix.c * point.y + matrix.e * 1;
	var y = matrix.b * point.x + matrix.d * point.y + matrix.f * 1;
	return {
		x : x,
		y : y
	}
}

/**
 * Returns the inverse matrix of the given SVG transformation matrix
 * 
 * @param {SVGTransformationMatrix}
 *            matrix
 * @return {Matrix}
 */
ORYX.Core.Math.getInverseMatrix = function(matrix) {

	var det = ORYX.Core.Math.getDeterminant(matrix), m = matrix;
	// +- -+
	// | a c e |
	// | b d f |
	// | 0 0 1 |
	// +- -+
	return {
		a : det * ((m.d * 1) - (m.f * 0)),
		b : det * ((m.f * 0) - (m.b * 1)),
		c : det * ((m.e * 0) - (m.c * 1)),
		d : det * ((m.a * 1) - (m.e * 0)),
		e : det * ((m.c * m.f) - (m.e * m.d)),
		f : det * ((m.e * m.b) - (m.a * m.f))
	}
}

/**
 * Returns the determinant of the svg transformation matrix
 * 
 * @param {SVGTranformationMatrix}
 *            matrix
 * @return {Number}
 * 
 */
ORYX.Core.Math.getDeterminant = function(m) {
	// a11a22a33+a12a23a31+a13a21a32-a13a22a31-a12a21a33-a11a23a32
	return (m.a * m.d * 1) + (m.c * m.f * 0) + (m.e * m.b * 0)
			- (m.e * m.d * 0) - (m.c * m.b * 1) - (m.a * m.f * 0);
}

/**
 * Returns the bounding box of the given node. Translates the origin bounding
 * box with the tranlation matrix.
 * 
 * @param {SVGElement}
 *            node
 * @return {Object} Includes x, y, width, height
 */
ORYX.Core.Math.getTranslatedBoundingBox = function(node) {
	var matrix = node.getCTM();
	var bb = node.getBBox();
	var ul = ORYX.Core.Math.getTranslatedPoint({
				x : bb.x,
				y : bb.y
			}, matrix);
	var ll = ORYX.Core.Math.getTranslatedPoint({
				x : bb.x,
				y : bb.y + bb.height
			}, matrix);
	var ur = ORYX.Core.Math.getTranslatedPoint({
				x : bb.x + bb.width,
				y : bb.y
			}, matrix);
	var lr = ORYX.Core.Math.getTranslatedPoint({
				x : bb.x + bb.width,
				y : bb.y + bb.height
			}, matrix);

	var minPoint = {
		x : Math.min(ul.x, ll.x, ur.x, lr.x),
		y : Math.min(ul.y, ll.y, ur.y, lr.y)
	}
	var maxPoint = {
		x : Math.max(ul.x, ll.x, ur.x, lr.x),
		y : Math.max(ul.y, ll.y, ur.y, lr.y)
	}
	return {
		x : minPoint.x,
		y : minPoint.y,
		width : maxPoint.x - minPoint.x,
		height : maxPoint.y - minPoint.y
	}
};

/**
 * Returns the angle of the given line, which is representated by the two points
 * 
 * @param {Point}
 *            p1
 * @param {Point}
 *            p2
 * @return {Number} 0 <= x <= 359.99999
 */
ORYX.Core.Math.getAngle = function(p1, p2) {
	if (p1.x == p2.x && p1.y == p2.y)
		return 0;

	var angle = Math.asin(Math.sqrt(Math.pow(p1.y - p2.y, 2))
			/ (Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p1.y - p2.y, 2))))
			* 180 / Math.PI;

	if (p2.x >= p1.x && p2.y <= p1.y)
		return angle;
	else if (p2.x < p1.x && p2.y <= p1.y)
		return 180 - angle;
	else if (p2.x < p1.x && p2.y > p1.y)
		return 180 + angle;
	else
		return 360 - angle;
};

/**
 * Implementation of the cohen-sutherland algorithm
 */
new function() {

	var RIGHT = 2, TOP = 8, BOTTOM = 4, LEFT = 1;

	function computeOutCode(x, y, xmin, ymin, xmax, ymax) {
		var code = 0;
		if (y > ymax)
			code |= TOP;
		else if (y < ymin)
			code |= BOTTOM;
		if (x > xmax)
			code |= RIGHT;
		else if (x < xmin)
			code |= LEFT;
		return code;
	}

	/**
	 * Returns TRUE if the rectangle is over the edge and has intersection
	 * points or includes it
	 * 
	 * @param {Object}
	 *            x1 Point A of the line
	 * @param {Object}
	 *            y1
	 * @param {Object}
	 *            x2 Point B of the line
	 * @param {Object}
	 *            y2
	 * @param {Object}
	 *            xmin Point A of the rectangle
	 * @param {Object}
	 *            ymin
	 * @param {Object}
	 *            xmax Point B of the rectangle
	 * @param {Object}
	 *            ymax
	 */
	ORYX.Core.Math.isRectOverLine = function(x1, y1, x2, y2, xmin, ymin, xmax,
			ymax) {
		return !!ORYX.Core.Math.clipLineOnRect.apply(ORYX.Core.Math, arguments);
	}

	/**
	 * Returns the clipped line on the given rectangle. If there is no
	 * intersection, it will return NULL.
	 * 
	 * @param {Object}
	 *            x1 Point A of the line
	 * @param {Object}
	 *            y1
	 * @param {Object}
	 *            x2 Point B of the line
	 * @param {Object}
	 *            y2
	 * @param {Object}
	 *            xmin Point A of the rectangle
	 * @param {Object}
	 *            ymin
	 * @param {Object}
	 *            xmax Point B of the rectangle
	 * @param {Object}
	 *            ymax
	 */
	ORYX.Core.Math.clipLineOnRect = function(x1, y1, x2, y2, xmin, ymin, xmax,
			ymax) {
		// Outcodes for P0, P1, and whatever point lies outside the clip
		// rectangle
		var outcode0, outcode1, outcodeOut, hhh = 0;
		var accept = false, done = false;

		// compute outcodes
		outcode0 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax);
		outcode1 = computeOutCode(x2, y2, xmin, ymin, xmax, ymax);

		do {
			if ((outcode0 | outcode1) == 0) {
				accept = true;
				done = true;
			} else if ((outcode0 & outcode1) > 0) {
				done = true;
			} else {
				// failed both tests, so calculate the line segment to clip
				// from an outside point to an intersection with clip edge
				var x = 0, y = 0;
				// At least one endpoint is outside the clip rectangle; pick it.
				outcodeOut = outcode0 != 0 ? outcode0 : outcode1;
				// Now find the intersection point;
				// use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)*
				// (y - y0)
				if ((outcodeOut & TOP) > 0) {
					x = x1 + (x2 - x1) * (ymax - y1) / (y2 - y1);
					y = ymax;
				} else if ((outcodeOut & BOTTOM) > 0) {
					x = x1 + (x2 - x1) * (ymin - y1) / (y2 - y1);
					y = ymin;
				} else if ((outcodeOut & RIGHT) > 0) {
					y = y1 + (y2 - y1) * (xmax - x1) / (x2 - x1);
					x = xmax;
				} else if ((outcodeOut & LEFT) > 0) {
					y = y1 + (y2 - y1) * (xmin - x1) / (x2 - x1);
					x = xmin;
				}

				// Now we move outside point to intersection point to clip
				// and get ready for next pass.
				if (outcodeOut == outcode0) {
					x1 = x;
					y1 = y;
					outcode0 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax);
				} else {
					x2 = x;
					y2 = y;
					outcode1 = computeOutCode(x2, y2, xmin, ymin, xmax, ymax);
				}
			}
			hhh++;
		} while (done != true && hhh < 5000);

		if (accept) {
			return {
				a : {
					x : x1,
					y : y1
				},
				b : {
					x : x2,
					y : y2
				}
			};
		}
		return null;
	}
}();

/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespace
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.StencilSet) {
	ORYX.Core.StencilSet = {};
}

/**
 * Class Stencil uses Prototpye 1.5.0 uses Inheritance
 * 
 * This class represents one stencil of a stencil set.
 */
ORYX.Core.StencilSet.Stencil = {

	/**
	 * Constructor
	 */
	construct : function(jsonStencil, namespace, source, stencilSet,
			propertyPackages, defaultPosition) {
		arguments.callee.$.construct.apply(this, arguments); // super();

		// check arguments and set defaults.
		if (!jsonStencil)
			throw "Stencilset seems corrupt.";
		if (!namespace)
			throw "Stencil does not provide namespace.";
		if (!source)
			throw "Stencil does not provide SVG source.";
		if (!stencilSet)
			throw "Fatal internal error loading stencilset.";
		// if(!propertyPackages) throw "Fatal internal error loading
		// stencilset.";

		this._source = source;
		this._jsonStencil = jsonStencil;
		this._stencilSet = stencilSet;
		this._namespace = namespace;
		this._propertyPackages = propertyPackages;

		if (defaultPosition && !this._jsonStencil.position)
			this._jsonStencil.position = defaultPosition;

		this._view;
		this._properties = new Hash();

		// check stencil consistency and set defaults.
		/*
		 * with(this._jsonStencil) {
		 * 
		 * if(!type) throw "Stencil does not provide type."; if((type != "edge") &&
		 * (type != "node")) throw "Stencil type must be 'edge' or 'node'.";
		 * if(!id || id == "") throw "Stencil does not provide valid id.";
		 * if(!title || title == "") throw "Stencil does not provide title";
		 * if(!description) { description = ""; }; if(!groups) { groups = []; }
		 * if(!roles) { roles = []; }
		 *  // add id of stencil to its roles roles.push(id); }
		 */

		// init all JSON values
		if (!this._jsonStencil.type
				|| !(this._jsonStencil.type === "edge" || this._jsonStencil.type === "node")) {
			throw "ORYX.Core.StencilSet.Stencil(construct): Type is not defined.";
		}
		if (!this._jsonStencil.id || this._jsonStencil.id === "") {
			throw "ORYX.Core.StencilSet.Stencil(construct): Id is not defined.";
		}
		if (!this._jsonStencil.title || this._jsonStencil.title === "") {
			throw "ORYX.Core.StencilSet.Stencil(construct): Title is not defined.";
		}

		if (!this._jsonStencil.description) {
			this._jsonStencil.description = "";
		};
		if (!this._jsonStencil.groups) {
			this._jsonStencil.groups = [];
		}
		if (!this._jsonStencil.roles) {
			this._jsonStencil.roles = [];
		}

		// add id of stencil to its roles
		this._jsonStencil.roles.push(this._jsonStencil.id);

		// prepend namespace to each role
		this._jsonStencil.roles.each((function(role, index) {
					this._jsonStencil.roles[index] = namespace + role;
				}).bind(this));

		// delete duplicate roles
		this._jsonStencil.roles = this._jsonStencil.roles.uniq();

		// make id unique by prepending namespace of stencil set
		this._jsonStencil.id = namespace + this._jsonStencil.id;

		this.postProcessProperties();

		// init serialize callback
		if (!this._jsonStencil.serialize) {
			this._jsonStencil.serialize = {};
			// this._jsonStencil.serialize = function(shape, data) { return
			// data;};
		}

		// init deserialize callback
		if (!this._jsonStencil.deserialize) {
			this._jsonStencil.deserialize = {};
			// this._jsonStencil.deserialize = function(shape, data) { return
			// data;};
		}

		// init layout callback
		if (!this._jsonStencil.layout) {
			this._jsonStencil.layout = []
			// this._jsonStencil.layout = function() {return true;}
		}

		// TODO does not work correctly, if the url does not exist
		// How to guarantee that the view is loaded correctly before leaving the
		// constructor???
		var url = source + "view/" + jsonStencil.view;
		// override content type when this is webkit.

		if (this._jsonStencil.view.trim().match(/</)) {
			var parser = new DOMParser();
			var xml = parser
					.parseFromString(this._jsonStencil.view, "text/xml");

			// check if result is a SVG document
			if (ORYX.Editor.checkClassType(xml.documentElement, SVGSVGElement)) {

				this._view = xml.documentElement;

			} else {
				throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnSuccess): The response is not a SVG document."
			}
		} else {
			new Ajax.Request(url, {
						asynchronous : false,
						method : 'get',
						onSuccess : this._loadSVGOnSuccess.bind(this),
						onFailure : this._loadSVGOnFailure.bind(this)
					});
		}
	},

	postProcessProperties : function() {

		// init property packages
		if (this._jsonStencil.propertyPackages
				&& this._jsonStencil.propertyPackages instanceof Array) {

			this._jsonStencil.propertyPackages.each((function(ppId) {
				var pp = this._propertyPackages[ppId];

				if (pp) {
					pp.each((function(prop) {
						var oProp = new ORYX.Core.StencilSet.Property(prop,
								this._namespace, this);
						this._properties[oProp.prefix() + "-" + oProp.id()] = oProp;

					}).bind(this));
				}
			}).bind(this));
		}

		// init properties
		if (this._jsonStencil.properties
				&& this._jsonStencil.properties instanceof Array) {
			this._jsonStencil.properties.each((function(prop) {
						var oProp = new ORYX.Core.StencilSet.Property(prop,
								this._namespace, this);
						this._properties[oProp.prefix() + "-" + oProp.id()] = oProp;
					}).bind(this));
		}

	},

	/**
	 * @param {ORYX.Core.StencilSet.Stencil}
	 *            stencil
	 * @return {Boolean} True, if stencil has the same namespace and type.
	 */
	equals : function(stencil) {
		return (this.id() === stencil.id());
	},

	stencilSet : function() {
		return this._stencilSet;
	},

	type : function() {
		return this._jsonStencil.type;
	},

	namespace : function() {
		return this._namespace;
	},

	id : function() {
		return this._jsonStencil.id;
	},

	idWithoutNs : function() {
		return this.id().replace(this.namespace(), "");
	},

	title : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonStencil, "title");
	},

	description : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonStencil,
				"description");
	},

	groups : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonStencil, "groups");
	},

	position : function() {
		return (isNaN(this._jsonStencil.position)
				? 0
				: this._jsonStencil.position);
	},

	view : function() {
		return this._view.cloneNode(true) || this._view;
	},

	icon : function() {
		return this._jsonStencil.icon;
	},

	fixedAspectRatio : function() {
		return this._jsonStencil.fixedAspectRatio === true;
	},

	hasMultipleRepositoryEntries : function() {
		return (this.getRepositoryEntries().length > 0);
	},

	getRepositoryEntries : function() {
		return (this._jsonStencil.repositoryEntries)
				? $A(this._jsonStencil.repositoryEntries)
				: $A([]);
	},

	properties : function() {
		return this._properties.values();
	},

	property : function(id) {
		return this._properties[id];
	},

	roles : function() {
		return this._jsonStencil.roles;
	},

	defaultAlign : function() {
		if (!this._jsonStencil.defaultAlign)
			return "east";
		return this._jsonStencil.defaultAlign;
	},

	serialize : function(shape, data) {
		return this._jsonStencil.serialize;
		// return this._jsonStencil.serialize(shape, data);
	},

	deserialize : function(shape, data) {
		return this._jsonStencil.deserialize;
		// return this._jsonStencil.deserialize(shape, data);
	},

	// in which case is targetShape used?
	// layout: function(shape, targetShape) {
	// return this._jsonStencil.layout(shape, targetShape);
	// },
	// layout property to store events for layouting in plugins
	layout : function(shape) {
		return this._jsonStencil.layout
	},

	addProperty : function(property, namespace) {
		if (property && namespace) {
			var oProp = new ORYX.Core.StencilSet.Property(property, namespace,
					this);
			this._properties[oProp.prefix() + "-" + oProp.id()] = oProp;
		}
	},

	removeProperty : function(propertyId) {
		if (propertyId) {
			var oProp = this._properties.values().find(function(prop) {
						return (propertyId == prop.id());
					});
			if (oProp)
				delete this._properties[oProp.prefix() + "-" + oProp.id()];
		}
	},

	_loadSVGOnSuccess : function(result) {

		var xml = null;

		/*
		 * We want to get a dom object for the requested file. Unfortunately,
		 * safari has some issues here. this is meant as a fallback for all
		 * browsers that don't recognize the svg mimetype as XML but support
		 * data: urls on Ajax calls.
		 */

		// responseXML != undefined.
		// if(!(result.responseXML))
		// get the dom by data: url.
		// xml = _evenMoreEvilHack(result.responseText, 'text/xml');
		// else
		// get it the usual way.
		xml = result.responseXML;

		// check if result is a SVG document
		if (ORYX.Editor.checkClassType(xml.documentElement, SVGSVGElement)) {

			this._view = xml.documentElement;

		} else {
			throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnSuccess): The response is not a SVG document."
		}
	},

	_loadSVGOnFailure : function(result) {
		throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnFailure): Loading SVG document failed."
	},

	toString : function() {
		return "Stencil " + this.title() + " (" + this.id() + ")";
	}
};

ORYX.Core.StencilSet.Stencil = Clazz.extend(ORYX.Core.StencilSet.Stencil);

/**
 * Transform a string into an xml document, the Safari way, as long as the
 * nightlies are broken. Even more evil version.
 * 
 * @param {Object}
 *            str
 * @param {Object}
 *            contentType
 */
function _evenMoreEvilHack(str, contentType) {

	/*
	 * This even more evil hack was taken from
	 * http://web-graphics.com/mtarchive/001606.php#chatty004999
	 */

	if (window.ActiveXObject) {
		var d = new ActiveXObject("MSXML.DomDocument");
		d.loadXML(str);
		return d;
	} else if (window.XMLHttpRequest) {
		var req = new XMLHttpRequest;
		req.open("GET", "data:" + (contentType || "application/xml")
						+ ";charset=utf-8," + encodeURIComponent(str), false);
		if (req.overrideMimeType) {
			req.overrideMimeType(contentType);
		}
		req.send(null);
		return req.responseXML;
	}
}

/**
 * Transform a string into an xml document, the Safari way, as long as the
 * nightlies are broken.
 * 
 * @param {Object}
 *            result the xml document object.
 */
function _evilSafariHack(serializedXML) {

	/*
	 * The Dave way. Taken from: http://web-graphics.com/mtarchive/001606.php
	 * 
	 * There is another possibility to parse XML in Safari, by implementing the
	 * DOMParser in javascript. However, in the latest nightlies of WebKit,
	 * DOMParser is already available, but still buggy. So, this is the best
	 * compromise for the time being.
	 */

	var xml = serializedXML;
	var url = "data:text/xml;charset=utf-8," + encodeURIComponent(xml);
	var dom = null;

	// your standard AJAX stuff
	var req = new XMLHttpRequest();
	req.open("GET", url);
	req.onload = function() {
		dom = req.responseXML;
	}
	req.send(null);

	return dom;
}
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespace
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.StencilSet) {
	ORYX.Core.StencilSet = {};
}

/**
 * Class Property uses Prototpye 1.5.0 uses Inheritance
 */
ORYX.Core.StencilSet.Property = Clazz.extend({

	/**
	 * Constructor
	 */
	construct : function(jsonProp, namespace, stencil) {
		arguments.callee.$.construct.apply(this, arguments);

		this._jsonProp = jsonProp
				|| ORYX.Log.error("Parameter jsonProp is not defined.");
		this._namespace = namespace
				|| ORYX.Log.error("Parameter namespace is not defined.");
		this._stencil = stencil
				|| ORYX.Log.error("Parameter stencil is not defined.");

		this._items = {};
		this._complexItems = {};

		// Flag to indicate whether or not the property should be hidden
		// This can be for example when the stencil set is upgraded, but the
		// model
		// has a value for that specific property filled in which we still want
		// to show.
		// If the value is missing, the property can simply be not shown.
		this._hidden = false;

		jsonProp.id = jsonProp.id
				|| ORYX.Log
						.error("ORYX.Core.StencilSet.Property(construct): Id is not defined.");
		jsonProp.id = jsonProp.id.toLowerCase();

		if (!jsonProp.type) {
			ORYX.Log
					.info(
							"Type is not defined for stencil '%0', id '%1'. Falling back to 'String'.",
							stencil, jsonProp.id);
			jsonProp.type = "string";
		} else {
			jsonProp.type = jsonProp.type.toLowerCase();
		}

		jsonProp.prefix = jsonProp.prefix || "oryx";
		jsonProp.title = jsonProp.title || "";
		jsonProp.value = jsonProp.value || "";
		jsonProp.description = jsonProp.description || "";
		jsonProp.readonly = jsonProp.readonly || false;
		jsonProp.optional = jsonProp.optional !== false;

		// init refToView
		if (this._jsonProp.refToView) {
			if (!(this._jsonProp.refToView instanceof Array)) {
				this._jsonProp.refToView = [this._jsonProp.refToView];
			}
		} else {
			this._jsonProp.refToView = [];
		}

		var globalMin = this.getMinForType(jsonProp.type);
		if (jsonProp.min === undefined || jsonProp.min === null) {
			jsonProp.min = globalMin;
		} else if (jsonProp.min < globalMin) {
			jsonProp.min = globalMin;
		}

		var globalMax = this.getMaxForType(jsonProp.type);
		if (jsonProp.max === undefined || jsonProp.max === null) {
			jsonProp.max = globalMax;
		} else if (jsonProp.max > globalMax) {
			jsonProp.min = globalMax;
		}

		if (!jsonProp.fillOpacity) {
			jsonProp.fillOpacity = false;
		}

		if ("number" != typeof jsonProp.lightness) {
			jsonProp.lightness = 1;
		} else {
			jsonProp.lightness = Math.max(0, Math.min(1, jsonProp.lightness));
		}

		if (!jsonProp.strokeOpacity) {
			jsonProp.strokeOpacity = false;
		}

		if (jsonProp.length === undefined || jsonProp.length === null) {
			jsonProp.length = Number.MAX_VALUE;
		}

		if (!jsonProp.wrapLines) {
			jsonProp.wrapLines = false;
		}

		if (!jsonProp.dateFormat) {
			jsonProp.dateFormat = ORYX.I18N.PropertyWindow.dateFormat
					|| "m/d/y";
		}

		if (!jsonProp.fill) {
			jsonProp.fill = false;
		}

		if (!jsonProp.stroke) {
			jsonProp.stroke = false;
		}

		if (!jsonProp.inverseBoolean) {
			jsonProp.inverseBoolean = false;
		}

		if (!jsonProp.directlyEditable && jsonProp.directlyEditable != false) {
			jsonProp.directlyEditable = true;
		}

		if (jsonProp.visible !== false) {
			jsonProp.visible = true;
		}

		if (jsonProp.isList !== true) {
			jsonProp.isList = false;

			if (!jsonProp.list || !(jsonProp.list instanceof Array)) {
				jsonProp.list = [];
			}
		}

		if (!jsonProp.category) {
			if (jsonProp.popular) {
				jsonProp.category = "popular";
			} else {
				jsonProp.category = "others";
			}
		}

		if (!jsonProp.alwaysAppearInMultiselect) {
			jsonProp.alwaysAppearInMultiselect = false;
		}

		if (jsonProp.type === ORYX.CONFIG.TYPE_CHOICE) {
			if (jsonProp.items && jsonProp.items instanceof Array) {
				jsonProp.items.each((function(jsonItem) {
					// why is the item's value used as the key???
					this._items[jsonItem.value.toLowerCase()] = new ORYX.Core.StencilSet.PropertyItem(
							jsonItem, namespace, this);
				}).bind(this));
			} else {
				throw "ORYX.Core.StencilSet.Property(construct): No property items defined."
			}
			// extended by Kerstin (start)
		} else if (jsonProp.type === ORYX.CONFIG.TYPE_COMPLEX
				|| jsonProp.type == ORYX.CONFIG.TYPE_MULTIPLECOMPLEX) {
			if (jsonProp.complexItems && jsonProp.complexItems instanceof Array) {
				jsonProp.complexItems.each((function(jsonComplexItem) {
					this._complexItems[jsonComplexItem.id.toLowerCase()] = new ORYX.Core.StencilSet.ComplexPropertyItem(
							jsonComplexItem, namespace, this);
				}).bind(this));
			}
		}
		// extended by Kerstin (end)
	},

	getMinForType : function(type) {
		if (type.toLowerCase() == ORYX.CONFIG.TYPE_INTEGER) {
			return -Math.pow(2, 31)
		} else {
			return -Number.MAX_VALUE + 1;
		}
	},
	getMaxForType : function(type) {
		if (type.toLowerCase() == ORYX.CONFIG.TYPE_INTEGER) {
			return Math.pow(2, 31) - 1
		} else {
			return Number.MAX_VALUE;
		}
	},

	/**
	 * @param {ORYX.Core.StencilSet.Property}
	 *            property
	 * @return {Boolean} True, if property has the same namespace and id.
	 */
	equals : function(property) {
		return (this._namespace === property.namespace() && this.id() === property
				.id()) ? true : false;
	},

	namespace : function() {
		return this._namespace;
	},

	stencil : function() {
		return this._stencil;
	},

	id : function() {
		return this._jsonProp.id;
	},

	prefix : function() {
		return this._jsonProp.prefix;
	},

	type : function() {
		return this._jsonProp.type;
	},

	inverseBoolean : function() {
		return this._jsonProp.inverseBoolean;
	},

	category : function() {
		return this._jsonProp.category;
	},

	setCategory : function(value) {
		this._jsonProp.category = value;
	},

	directlyEditable : function() {
		return this._jsonProp.directlyEditable;
	},

	visible : function() {
		return this._jsonProp.visible;
	},

	title : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonProp, "title");
	},

	value : function() {
		return this._jsonProp.value;
	},

	readonly : function() {
		return this._jsonProp.readonly;
	},

	optional : function() {
		return this._jsonProp.optional;
	},

	description : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonProp,
				"description");
	},

	/**
	 * An optional link to a SVG element so that the property affects the
	 * graphical representation of the stencil.
	 */
	refToView : function() {
		return this._jsonProp.refToView;
	},

	/**
	 * If type is integer or float, min is the lower bounds of value.
	 */
	min : function() {
		return this._jsonProp.min;
	},

	/**
	 * If type ist integer or float, max is the upper bounds of value.
	 */
	max : function() {
		return this._jsonProp.max;
	},

	/**
	 * If type is float, this method returns if the fill-opacity property should
	 * be set.
	 * 
	 * @return {Boolean}
	 */
	fillOpacity : function() {
		return this._jsonProp.fillOpacity;
	},

	/**
	 * If type is float, this method returns if the stroke-opacity property
	 * should be set.
	 * 
	 * @return {Boolean}
	 */
	strokeOpacity : function() {
		return this._jsonProp.strokeOpacity;
	},

	/**
	 * If type is string or richtext, length is the maximum length of the text.
	 * TODO how long can a string be.
	 */
	length : function() {
		return this._jsonProp.length ? this._jsonProp.length : Number.MAX_VALUE;
	},

	wrapLines : function() {
		return this._jsonProp.wrapLines;
	},

	/**
	 * If type is date, dateFormat specifies the format of the date. The format
	 * specification of the ext library is used:
	 * 
	 * Format Output Description ------ ----------
	 * -------------------------------------------------------------- d 10 Day
	 * of the month, 2 digits with leading zeros D Wed A textual representation
	 * of a day, three letters j 10 Day of the month without leading zeros l
	 * Wednesday A full textual representation of the day of the week S th
	 * English ordinal day of month suffix, 2 chars (use with j) w 3 Numeric
	 * representation of the day of the week z 9 The julian date, or day of the
	 * year (0-365) W 01 ISO-8601 2-digit week number of year, weeks starting on
	 * Monday (00-52) F January A full textual representation of the month m 01
	 * Numeric representation of a month, with leading zeros M Jan Month name
	 * abbreviation, three letters n 1 Numeric representation of a month,
	 * without leading zeros t 31 Number of days in the given month L 0 Whether
	 * its a leap year (1 if it is a leap year, else 0) Y 2007 A full numeric
	 * representation of a year, 4 digits y 07 A two digit representation of a
	 * year a pm Lowercase Ante meridiem and Post meridiem A PM Uppercase Ante
	 * meridiem and Post meridiem g 3 12-hour format of an hour without leading
	 * zeros G 15 24-hour format of an hour without leading zeros h 03 12-hour
	 * format of an hour with leading zeros H 15 24-hour format of an hour with
	 * leading zeros i 05 Minutes with leading zeros s 01 Seconds, with leading
	 * zeros O -0600 Difference to Greenwich time (GMT) in hours T CST Timezone
	 * setting of the machine running the code Z -21600 Timezone offset in
	 * seconds (negative if west of UTC, positive if east)
	 * 
	 * Example: F j, Y, g:i a -> January 10, 2007, 3:05 pm
	 */
	dateFormat : function() {
		return this._jsonProp.dateFormat;
	},

	/**
	 * If type is color, this method returns if the fill property should be set.
	 * 
	 * @return {Boolean}
	 */
	fill : function() {
		return this._jsonProp.fill;
	},

	/**
	 * Lightness defines the satiation of the color 0 is the pure color 1 is
	 * white
	 * 
	 * @return {Integer} lightness
	 */
	lightness : function() {
		return this._jsonProp.lightness;
	},

	/**
	 * If type is color, this method returns if the stroke property should be
	 * set.
	 * 
	 * @return {Boolean}
	 */
	stroke : function() {
		return this._jsonProp.stroke;
	},

	/**
	 * If type is choice, items is a hash map with all alternative values
	 * (PropertyItem objects) with id as keys.
	 */
	items : function() {
		return $H(this._items).values();
	},

	item : function(value) {
		if (value) {
			return this._items[value.toLowerCase()];
		} else {
			return null;
		}
	},

	toString : function() {
		return "Property " + this.title() + " (" + this.id() + ")";
	},

	complexItems : function() {
		return $H(this._complexItems).values();
	},

	complexItem : function(id) {
		if (id) {
			return this._complexItems[id.toLowerCase()];
		} else {
			return null;
		}

	},

	complexAttributeToView : function() {
		return this._jsonProp.complexAttributeToView || "";
	},

	isList : function() {
		return !!this._jsonProp.isList;
	},

	getListItems : function() {
		return this._jsonProp.list;
	},

	/**
	 * If type is glossary link, the type of category can be defined where the
	 * link only can go to.
	 * 
	 * @return {String} The glossary category id
	 */
	linkableType : function() {
		return this._jsonProp.linkableType || "";
	},

	alwaysAppearInMultiselect : function() {
		return this._jsonProp.alwaysAppearInMultiselect;
	},

	popular : function() {
		return this._jsonProp.popular || false;
	},

	setPopular : function() {
		this._jsonProp.popular = true;
	},

	hide : function() {
		this._hidden = true;
	},

	isHidden : function() {
		return this._hidden;
	}

});
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespace
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.StencilSet) {
	ORYX.Core.StencilSet = {};
}

/**
 * Class Stencil uses Prototpye 1.5.0 uses Inheritance
 */
ORYX.Core.StencilSet.PropertyItem = Clazz.extend({

	/**
	 * Constructor
	 */
	construct : function(jsonItem, namespace, property) {
		arguments.callee.$.construct.apply(this, arguments);

		if (!jsonItem) {
			throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter jsonItem is not defined.";
		}
		if (!namespace) {
			throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter namespace is not defined.";
		}
		if (!property) {
			throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter property is not defined.";
		}

		this._jsonItem = jsonItem;
		this._namespace = namespace;
		this._property = property;

		// init all values
		if (!jsonItem.value) {
			throw "ORYX.Core.StencilSet.PropertyItem(construct): Value is not defined.";
		}

		if (this._jsonItem.refToView) {
			if (!(this._jsonItem.refToView instanceof Array)) {
				this._jsonItem.refToView = [this._jsonItem.refToView];
			}
		} else {
			this._jsonItem.refToView = [];
		}
	},

	/**
	 * @param {ORYX.Core.StencilSet.PropertyItem}
	 *            item
	 * @return {Boolean} True, if item has the same namespace and id.
	 */
	equals : function(item) {
		return (this.property().equals(item.property()) && this.value() === item
				.value());
	},

	namespace : function() {
		return this._namespace;
	},

	property : function() {
		return this._property;
	},

	value : function() {
		return this._jsonItem.value;
	},

	title : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonItem, "title");
	},

	refToView : function() {
		return this._jsonItem.refToView;
	},

	icon : function() {
		return (this._jsonItem.icon) ? this.property().stencil()._source
				+ "icons/" + this._jsonItem.icon : "";
	},

	toString : function() {
		return "PropertyItem " + this.property() + " (" + this.value() + ")";
	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.StencilSet) {
	ORYX.Core.StencilSet = {};
}

/**
 * Class Stencil uses Prototpye 1.5.0 uses Inheritance
 */
ORYX.Core.StencilSet.ComplexPropertyItem = Clazz.extend({

	/**
	 * Constructor
	 */
	construct : function(jsonItem, namespace, property) {
		arguments.callee.$.construct.apply(this, arguments);

		if (!jsonItem) {
			throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter jsonItem is not defined.";
		}
		if (!namespace) {
			throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter namespace is not defined.";
		}
		if (!property) {
			throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter property is not defined.";
		}

		this._jsonItem = jsonItem;
		this._namespace = namespace;
		this._property = property;
		this._items = new Hash();
		this._complexItems = new Hash();

		// init all values
		if (!jsonItem.name) {
			throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Name is not defined.";
		}

		if (!jsonItem.type) {
			throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Type is not defined.";
		} else {
			jsonItem.type = jsonItem.type.toLowerCase();
		}

		if (jsonItem.type === ORYX.CONFIG.TYPE_CHOICE) {
			if (jsonItem.items && jsonItem.items instanceof Array) {
				jsonItem.items.each((function(item) {
					this._items[item.value] = new ORYX.Core.StencilSet.PropertyItem(
							item, namespace, this);
				}).bind(this));
			} else {
				throw "ORYX.Core.StencilSet.Property(construct): No property items defined."
			}
		} else if (jsonItem.type === ORYX.CONFIG.TYPE_COMPLEX) {
			if (jsonItem.complexItems && jsonItem.complexItems instanceof Array) {
				jsonItem.complexItems.each((function(complexItem) {
					this._complexItems[complexItem.id] = new ORYX.Core.StencilSet.ComplexPropertyItem(
							complexItem, namespace, this);
				}).bind(this));
			} else {
				throw "ORYX.Core.StencilSet.Property(construct): No property items defined."
			}
		}
	},

	/**
	 * @param {ORYX.Core.StencilSet.PropertyItem}
	 *            item
	 * @return {Boolean} True, if item has the same namespace and id.
	 */
	equals : function(item) {
		return (this.property().equals(item.property()) && this.name() === item
				.name());
	},

	namespace : function() {
		return this._namespace;
	},

	property : function() {
		return this._property;
	},

	name : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonItem, "name");
	},

	id : function() {
		return this._jsonItem.id;
	},

	type : function() {
		return this._jsonItem.type;
	},

	optional : function() {
		return this._jsonItem.optional;
	},

	width : function() {
		return this._jsonItem.width;
	},

	value : function() {
		return this._jsonItem.value;
	},

	items : function() {
		return this._items.values();
	},

	complexItems : function() {
		return this._complexItems.values();
	},

	disable : function() {
		return this._jsonItem.disable;
	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.StencilSet) {
	ORYX.Core.StencilSet = {};
}

/**
 * Class Rules uses Prototpye 1.5.0 uses Inheritance
 * 
 * This class implements the API to check the stencil sets' rules.
 */
ORYX.Core.StencilSet.Rules = {

	/**
	 * Constructor
	 */
	construct : function() {
		arguments.callee.$.construct.apply(this, arguments);

		this._stencilSets = [];
		this._stencils = [];
		this._containerStencils = [];

		this._cachedConnectSET = new Hash();
		this._cachedConnectSE = new Hash();
		this._cachedConnectTE = new Hash();
		this._cachedCardSE = new Hash();
		this._cachedCardTE = new Hash();
		this._cachedContainPC = new Hash();
		this._cachedMorphRS = new Hash();

		this._connectionRules = new Hash();
		this._cardinalityRules = new Hash();
		this._containmentRules = new Hash();
		this._morphingRules = new Hash();
		this._layoutRules = new Hash();
	},

	/**
	 * Call this method to initialize the rules for a stencil set and all of its
	 * active extensions.
	 * 
	 * @param {Object}
	 *            stencilSet
	 */
	initializeRules : function(stencilSet) {

		var existingSS = this._stencilSets.find(function(ss) {
					return (ss.namespace() == stencilSet.namespace());
				});
		if (existingSS) {
			// reinitialize all rules
			var stencilsets = this._stencilSets.clone();
			stencilsets = stencilsets.without(existingSS);
			stencilsets.push(stencilSet);

			this._stencilSets = [];
			this._stencils = [];
			this._containerStencils = [];

			this._cachedConnectSET = new Hash();
			this._cachedConnectSE = new Hash();
			this._cachedConnectTE = new Hash();
			this._cachedCardSE = new Hash();
			this._cachedCardTE = new Hash();
			this._cachedContainPC = new Hash();
			this._cachedMorphRS = new Hash();

			this._connectionRules = new Hash();
			this._cardinalityRules = new Hash();
			this._containmentRules = new Hash();
			this._morphingRules = new Hash();
			this._layoutRules = new Hash();

			stencilsets.each(function(ss) {
						this.initializeRules(ss);
					}.bind(this));
			return;
		} else {
			this._stencilSets.push(stencilSet);

			var jsonRules = new Hash(stencilSet.jsonRules());
			var namespace = stencilSet.namespace();
			var stencils = stencilSet.stencils();

			stencilSet.extensions().values().each(function(extension) {
				if (extension.rules) {
					if (extension.rules.connectionRules)
						jsonRules.connectionRules = jsonRules.connectionRules
								.concat(extension.rules.connectionRules);
					if (extension.rules.cardinalityRules)
						jsonRules.cardinalityRules = jsonRules.cardinalityRules
								.concat(extension.rules.cardinalityRules);
					if (extension.rules.containmentRules)
						jsonRules.containmentRules = jsonRules.containmentRules
								.concat(extension.rules.containmentRules);
					if (extension.rules.morphingRules)
						jsonRules.morphingRules = jsonRules.morphingRules
								.concat(extension.rules.morphingRules);
				}
				if (extension.stencils)
					stencils = stencils.concat(extension.stencils);
			});

			this._stencils = this._stencils.concat(stencilSet.stencils());

			// init connection rules
			var cr = this._connectionRules;
			if (jsonRules.connectionRules) {
				jsonRules.connectionRules.each((function(rules) {
					if (this._isRoleOfOtherNamespace(rules.role)) {
						if (!cr[rules.role]) {
							cr[rules.role] = new Hash();
						}
					} else {
						if (!cr[namespace + rules.role])
							cr[namespace + rules.role] = new Hash();
					}

					rules.connects.each((function(connect) {
								var toRoles = [];
								if (connect.to) {
									if (!(connect.to instanceof Array)) {
										connect.to = [connect.to];
									}
									connect.to.each((function(to) {
												if (this
														._isRoleOfOtherNamespace(to)) {
													toRoles.push(to);
												} else {
													toRoles
															.push(namespace
																	+ to);
												}
											}).bind(this));
								}

								var role, from;
								if (this._isRoleOfOtherNamespace(rules.role))
									role = rules.role;
								else
									role = namespace + rules.role;

								if (this._isRoleOfOtherNamespace(connect.from))
									from = connect.from;
								else
									from = namespace + connect.from;

								if (!cr[role][from])
									cr[role][from] = toRoles;
								else
									cr[role][from] = cr[role][from]
											.concat(toRoles);

							}).bind(this));
				}).bind(this));
			}

			// init cardinality rules
			var cardr = this._cardinalityRules;
			if (jsonRules.cardinalityRules) {
				jsonRules.cardinalityRules.each((function(rules) {
					var cardrKey;
					if (this._isRoleOfOtherNamespace(rules.role)) {
						cardrKey = rules.role;
					} else {
						cardrKey = namespace + rules.role;
					}

					if (!cardr[cardrKey]) {
						cardr[cardrKey] = {};
						for (i in rules) {
							cardr[cardrKey][i] = rules[i];
						}
					}

					var oe = new Hash();
					if (rules.outgoingEdges) {
						rules.outgoingEdges.each((function(rule) {
									if (this._isRoleOfOtherNamespace(rule.role)) {
										oe[rule.role] = rule;
									} else {
										oe[namespace + rule.role] = rule;
									}
								}).bind(this));
					}
					cardr[cardrKey].outgoingEdges = oe;
					var ie = new Hash();
					if (rules.incomingEdges) {
						rules.incomingEdges.each((function(rule) {
									if (this._isRoleOfOtherNamespace(rule.role)) {
										ie[rule.role] = rule;
									} else {
										ie[namespace + rule.role] = rule;
									}
								}).bind(this));
					}
					cardr[cardrKey].incomingEdges = ie;
				}).bind(this));
			}

			// init containment rules
			var conr = this._containmentRules;
			if (jsonRules.containmentRules) {
				jsonRules.containmentRules.each((function(rules) {
					var conrKey;
					if (this._isRoleOfOtherNamespace(rules.role)) {
						conrKey = rules.role;
					} else {
						this._containerStencils.push(namespace + rules.role);
						conrKey = namespace + rules.role;
					}
					if (!conr[conrKey]) {
						conr[conrKey] = [];
					}
					(rules.contains || []).each((function(containRole) {
								if (this._isRoleOfOtherNamespace(containRole)) {
									conr[conrKey].push(containRole);
								} else {
									conr[conrKey].push(namespace + containRole);
								}
							}).bind(this));
				}).bind(this));
			}

			// init morphing rules
			var morphr = this._morphingRules;
			if (jsonRules.morphingRules) {
				jsonRules.morphingRules.each((function(rules) {
							var morphrKey;
							if (this._isRoleOfOtherNamespace(rules.role)) {
								morphrKey = rules.role;
							} else {
								morphrKey = namespace + rules.role;
							}
							if (!morphr[morphrKey]) {
								morphr[morphrKey] = [];
							}
							if (!rules.preserveBounds) {
								rules.preserveBounds = false;
							}
							rules.baseMorphs.each(
									(function(baseMorphStencilId) {
										var morphStencil = this
												._getStencilById(namespace
														+ baseMorphStencilId);
										if (morphStencil) {
											morphr[morphrKey]
													.push(morphStencil);
										}
									}).bind(this));
						}).bind(this));
			}

			// init layouting rules
			var layoutRules = this._layoutRules;
			if (jsonRules.layoutRules) {

				var getDirections = function(o) {
					return {
						"edgeRole" : o.edgeRole || undefined,
						"t" : o["t"] || 1,
						"r" : o["r"] || 1,
						"b" : o["b"] || 1,
						"l" : o["l"] || 1
					}
				}

				jsonRules.layoutRules.each(function(rules) {
					var layoutKey;
					if (this._isRoleOfOtherNamespace(rules.role)) {
						layoutKey = rules.role;
					} else {
						layoutKey = namespace + rules.role;
					}
					if (!layoutRules[layoutKey]) {
						layoutRules[layoutKey] = {};
					}
					if (rules["in"]) {
						layoutRules[layoutKey]["in"] = getDirections(rules["in"]);
					}
					if (rules["ins"]) {
						layoutRules[layoutKey]["ins"] = (rules["ins"] || [])
								.map(function(e) {
											return getDirections(e)
										})
					}
					if (rules["out"]) {
						layoutRules[layoutKey]["out"] = getDirections(rules["out"]);
					}
					if (rules["outs"]) {
						layoutRules[layoutKey]["outs"] = (rules["outs"] || [])
								.map(function(e) {
											return getDirections(e)
										})
					}
				}.bind(this));
			}
		}
	},

	_getStencilById : function(id) {
		return this._stencils.find(function(stencil) {
					return stencil.id() == id;
				});
	},

	_cacheConnect : function(args) {
		result = this._canConnect(args);

		if (args.sourceStencil && args.targetStencil) {
			var source = this._cachedConnectSET[args.sourceStencil.id()];

			if (!source) {
				source = new Hash();
				this._cachedConnectSET[args.sourceStencil.id()] = source;
			}

			var edge = source[args.edgeStencil.id()];

			if (!edge) {
				edge = new Hash();
				source[args.edgeStencil.id()] = edge;
			}

			edge[args.targetStencil.id()] = result;

		} else if (args.sourceStencil) {
			var source = this._cachedConnectSE[args.sourceStencil.id()];

			if (!source) {
				source = new Hash();
				this._cachedConnectSE[args.sourceStencil.id()] = source;
			}

			source[args.edgeStencil.id()] = result;

		} else {
			var target = this._cachedConnectTE[args.targetStencil.id()];

			if (!target) {
				target = new Hash();
				this._cachedConnectTE[args.targetStencil.id()] = target;
			}

			target[args.edgeStencil.id()] = result;
		}

		return result;
	},

	_cacheCard : function(args) {

		if (args.sourceStencil) {
			var source = this._cachedCardSE[args.sourceStencil.id()]

			if (!source) {
				source = new Hash();
				this._cachedCardSE[args.sourceStencil.id()] = source;
			}

			var max = this._getMaximumNumberOfOutgoingEdge(args);
			if (max == undefined)
				max = -1;

			source[args.edgeStencil.id()] = max;
		}

		if (args.targetStencil) {
			var target = this._cachedCardTE[args.targetStencil.id()]

			if (!target) {
				target = new Hash();
				this._cachedCardTE[args.targetStencil.id()] = target;
			}

			var max = this._getMaximumNumberOfIncomingEdge(args);
			if (max == undefined)
				max = -1;

			target[args.edgeStencil.id()] = max;
		}
	},

	_cacheContain : function(args) {

		var result = [
				this._canContain(args),
				this._getMaximumOccurrence(args.containingStencil,
						args.containedStencil)]

		if (result[1] == undefined)
			result[1] = -1;

		var children = this._cachedContainPC[args.containingStencil.id()];

		if (!children) {
			children = new Hash();
			this._cachedContainPC[args.containingStencil.id()] = children;
		}

		children[args.containedStencil.id()] = result;

		return result;
	},

	/**
	 * Returns all stencils belonging to a morph group. (calculation result is
	 * cached)
	 */
	_cacheMorph : function(role) {

		var morphs = this._cachedMorphRS[role];

		if (!morphs) {
			morphs = [];

			if (this._morphingRules.keys().include(role)) {
				morphs = this._stencils.select(function(stencil) {
							return stencil.roles().include(role);
						});
			}

			this._cachedMorphRS[role] = morphs;
		}
		return morphs;
	},

	/** Begin connection rules' methods */

	/**
	 * 
	 * @param {Object}
	 *            args sourceStencil: ORYX.Core.StencilSet.Stencil | undefined
	 *            sourceShape: ORYX.Core.Shape | undefined
	 * 
	 * At least sourceStencil or sourceShape has to be specified
	 * 
	 * @return {Array} Array of stencils of edges that can be outgoing edges of
	 *         the source.
	 */
	outgoingEdgeStencils : function(args) {
		// check arguments
		if (!args.sourceShape && !args.sourceStencil) {
			return [];
		}

		// init arguments
		if (args.sourceShape) {
			args.sourceStencil = args.sourceShape.getStencil();
		}

		var _edges = [];

		// test each edge, if it can connect to source
		this._stencils.each((function(stencil) {
					if (stencil.type() === "edge") {
						var newArgs = Object.clone(args);
						newArgs.edgeStencil = stencil;
						if (this.canConnect(newArgs)) {
							_edges.push(stencil);
						}
					}
				}).bind(this));

		return _edges;
	},

	/**
	 * 
	 * @param {Object}
	 *            args targetStencil: ORYX.Core.StencilSet.Stencil | undefined
	 *            targetShape: ORYX.Core.Shape | undefined
	 * 
	 * At least targetStencil or targetShape has to be specified
	 * 
	 * @return {Array} Array of stencils of edges that can be incoming edges of
	 *         the target.
	 */
	incomingEdgeStencils : function(args) {
		// check arguments
		if (!args.targetShape && !args.targetStencil) {
			return [];
		}

		// init arguments
		if (args.targetShape) {
			args.targetStencil = args.targetShape.getStencil();
		}

		var _edges = [];

		// test each edge, if it can connect to source
		this._stencils.each((function(stencil) {
					if (stencil.type() === "edge") {
						var newArgs = Object.clone(args);
						newArgs.edgeStencil = stencil;
						if (this.canConnect(newArgs)) {
							_edges.push(stencil);
						}
					}
				}).bind(this));

		return _edges;
	},

	/**
	 * 
	 * @param {Object}
	 *            args edgeStencil: ORYX.Core.StencilSet.Stencil | undefined
	 *            edgeShape: ORYX.Core.Edge | undefined targetStencil:
	 *            ORYX.Core.StencilSet.Stencil | undefined targetShape:
	 *            ORYX.Core.Node | undefined
	 * 
	 * At least edgeStencil or edgeShape has to be specified!!!
	 * 
	 * @return {Array} Returns an array of stencils that can be source of the
	 *         specified edge.
	 */
	sourceStencils : function(args) {
		// check arguments
		if (!args || !args.edgeShape && !args.edgeStencil) {
			return [];
		}

		// init arguments
		if (args.targetShape) {
			args.targetStencil = args.targetShape.getStencil();
		}

		if (args.edgeShape) {
			args.edgeStencil = args.edgeShape.getStencil();
		}

		var _sources = [];

		// check each stencil, if it can be a source
		this._stencils.each((function(stencil) {
					var newArgs = Object.clone(args);
					newArgs.sourceStencil = stencil;
					if (this.canConnect(newArgs)) {
						_sources.push(stencil);
					}
				}).bind(this));

		return _sources;
	},

	/**
	 * 
	 * @param {Object}
	 *            args edgeStencil: ORYX.Core.StencilSet.Stencil | undefined
	 *            edgeShape: ORYX.Core.Edge | undefined sourceStencil:
	 *            ORYX.Core.StencilSet.Stencil | undefined sourceShape:
	 *            ORYX.Core.Node | undefined
	 * 
	 * At least edgeStencil or edgeShape has to be specified!!!
	 * 
	 * @return {Array} Returns an array of stencils that can be target of the
	 *         specified edge.
	 */
	targetStencils : function(args) {
		// check arguments
		if (!args || !args.edgeShape && !args.edgeStencil) {
			return [];
		}

		// init arguments
		if (args.sourceShape) {
			args.sourceStencil = args.sourceShape.getStencil();
		}

		if (args.edgeShape) {
			args.edgeStencil = args.edgeShape.getStencil();
		}

		var _targets = [];

		// check stencil, if it can be a target
		this._stencils.each((function(stencil) {
					var newArgs = Object.clone(args);
					newArgs.targetStencil = stencil;
					if (this.canConnect(newArgs)) {
						_targets.push(stencil);
					}
				}).bind(this));

		return _targets;
	},

	/**
	 * 
	 * @param {Object}
	 *            args edgeStencil: ORYX.Core.StencilSet.Stencil edgeShape:
	 *            ORYX.Core.Edge |undefined sourceStencil:
	 *            ORYX.Core.StencilSet.Stencil | undefined sourceShape:
	 *            ORYX.Core.Node |undefined targetStencil:
	 *            ORYX.Core.StencilSet.Stencil | undefined targetShape:
	 *            ORYX.Core.Node |undefined
	 * 
	 * At least source or target has to be specified!!!
	 * 
	 * @return {Boolean} Returns, if the edge can connect source and target.
	 */
	canConnect : function(args) {
		// check arguments
		if (!args
				|| (!args.sourceShape && !args.sourceStencil
						&& !args.targetShape && !args.targetStencil)
				|| !args.edgeShape && !args.edgeStencil) {
			return false;
		}

		// init arguments
		if (args.sourceShape) {
			args.sourceStencil = args.sourceShape.getStencil();
		}
		if (args.targetShape) {
			args.targetStencil = args.targetShape.getStencil();
		}
		if (args.edgeShape) {
			args.edgeStencil = args.edgeShape.getStencil();
		}

		var result;

		if (args.sourceStencil && args.targetStencil) {
			var source = this._cachedConnectSET[args.sourceStencil.id()];

			if (!source)
				result = this._cacheConnect(args);
			else {
				var edge = source[args.edgeStencil.id()];

				if (!edge)
					result = this._cacheConnect(args);
				else {
					var target = edge[args.targetStencil.id()];

					if (target == undefined)
						result = this._cacheConnect(args);
					else
						result = target;
				}
			}
		} else if (args.sourceStencil) {
			var source = this._cachedConnectSE[args.sourceStencil.id()];

			if (!source)
				result = this._cacheConnect(args);
			else {
				var edge = source[args.edgeStencil.id()];

				if (edge == undefined)
					result = this._cacheConnect(args);
				else
					result = edge;
			}
		} else { // args.targetStencil
			var target = this._cachedConnectTE[args.targetStencil.id()];

			if (!target)
				result = this._cacheConnect(args);
			else {
				var edge = target[args.edgeStencil.id()];

				if (edge == undefined)
					result = this._cacheConnect(args);
				else
					result = edge;
			}
		}

		// check cardinality
		if (result) {
			if (args.sourceShape) {
				var source = this._cachedCardSE[args.sourceStencil.id()];

				if (!source) {
					this._cacheCard(args);
					source = this._cachedCardSE[args.sourceStencil.id()];
				}

				var max = source[args.edgeStencil.id()];

				if (max == undefined) {
					this._cacheCard(args);
				}

				max = source[args.edgeStencil.id()];

				if (max != -1) {
					result = args.sourceShape.getOutgoingShapes().all(
							function(cs) {
								if ((cs.getStencil().id() === args.edgeStencil
										.id())
										&& ((args.edgeShape)
												? cs !== args.edgeShape
												: true)) {
									max--;
									return (max > 0) ? true : false;
								} else {
									return true;
								}
							});
				}
			}

			if (args.targetShape) {
				var target = this._cachedCardTE[args.targetStencil.id()];

				if (!target) {
					this._cacheCard(args);
					target = this._cachedCardTE[args.targetStencil.id()];
				}

				var max = target[args.edgeStencil.id()];

				if (max == undefined) {
					this._cacheCard(args);
				}

				max = target[args.edgeStencil.id()];

				if (max != -1) {
					result = args.targetShape.getIncomingShapes().all(
							function(cs) {
								if ((cs.getStencil().id() === args.edgeStencil
										.id())
										&& ((args.edgeShape)
												? cs !== args.edgeShape
												: true)) {
									max--;
									return (max > 0) ? true : false;
								} else {
									return true;
								}
							});
				}
			}
		}

		return result;
	},

	/**
	 * 
	 * @param {Object}
	 *            args edgeStencil: ORYX.Core.StencilSet.Stencil edgeShape:
	 *            ORYX.Core.Edge |undefined sourceStencil:
	 *            ORYX.Core.StencilSet.Stencil | undefined sourceShape:
	 *            ORYX.Core.Node |undefined targetStencil:
	 *            ORYX.Core.StencilSet.Stencil | undefined targetShape:
	 *            ORYX.Core.Node |undefined
	 * 
	 * At least source or target has to be specified!!!
	 * 
	 * @return {Boolean} Returns, if the edge can connect source and target.
	 */
	_canConnect : function(args) {
		// check arguments
		if (!args
				|| (!args.sourceShape && !args.sourceStencil
						&& !args.targetShape && !args.targetStencil)
				|| !args.edgeShape && !args.edgeStencil) {
			return false;
		}

		// init arguments
		if (args.sourceShape) {
			args.sourceStencil = args.sourceShape.getStencil();
		}
		if (args.targetShape) {
			args.targetStencil = args.targetShape.getStencil();
		}
		if (args.edgeShape) {
			args.edgeStencil = args.edgeShape.getStencil();
		}

		// 1. check connection rules
		var resultCR;

		// get all connection rules for this edge
		var edgeRules = this._getConnectionRulesOfEdgeStencil(args.edgeStencil);

		// check connection rules, if the source can be connected to the target
		// with the specified edge.
		if (edgeRules.keys().length === 0) {
			resultCR = false;
		} else {
			if (args.sourceStencil) {
				resultCR = args.sourceStencil.roles().any(function(sourceRole) {
					var targetRoles = edgeRules[sourceRole];

					if (!targetRoles) {
						return false;
					}

					if (args.targetStencil) {
						return (targetRoles.any(function(targetRole) {
									return args.targetStencil.roles()
											.member(targetRole);
								}));
					} else {
						return true;
					}
				});
			} else { // !args.sourceStencil -> there is args.targetStencil
				resultCR = edgeRules.values().any(function(targetRoles) {
							return args.targetStencil.roles().any(
									function(targetRole) {
										return targetRoles.member(targetRole);
									});
						});
			}
		}

		return resultCR;
	},

	/** End connection rules' methods */

	/** Begin containment rules' methods */

	isContainer : function(shape) {
		return this._containerStencils.member(shape.getStencil().id());
	},

	/**
	 * 
	 * @param {Object}
	 *            args containingStencil: ORYX.Core.StencilSet.Stencil
	 *            containingShape: ORYX.Core.AbstractShape containedStencil:
	 *            ORYX.Core.StencilSet.Stencil containedShape: ORYX.Core.Shape
	 */
	canContain : function(args) {
		if (!args || !args.containingStencil && !args.containingShape
				|| !args.containedStencil && !args.containedShape) {
			return false;
		}

		// init arguments
		if (args.containedShape) {
			args.containedStencil = args.containedShape.getStencil();
		}

		if (args.containingShape) {
			args.containingStencil = args.containingShape.getStencil();
		}

		// if(args.containingStencil.type() == 'edge' ||
		// args.containedStencil.type() == 'edge')
		// return false;
		if (args.containedStencil.type() == 'edge')
			return false;

		var childValues;

		var parent = this._cachedContainPC[args.containingStencil.id()];

		if (!parent)
			childValues = this._cacheContain(args);
		else {
			childValues = parent[args.containedStencil.id()];

			if (!childValues)
				childValues = this._cacheContain(args);
		}

		if (!childValues[0])
			return false;
		else if (childValues[1] == -1)
			return true;
		else {
			if (args.containingShape) {
				var max = childValues[1];
				return args.containingShape.getChildShapes(false).all(
						function(as) {
							if (as.getStencil().id() === args.containedStencil
									.id()) {
								max--;
								return (max > 0) ? true : false;
							} else {
								return true;
							}
						});
			} else {
				return true;
			}
		}
	},

	/**
	 * 
	 * @param {Object}
	 *            args containingStencil: ORYX.Core.StencilSet.Stencil
	 *            containingShape: ORYX.Core.AbstractShape containedStencil:
	 *            ORYX.Core.StencilSet.Stencil containedShape: ORYX.Core.Shape
	 */
	_canContain : function(args) {
		if (!args || !args.containingStencil && !args.containingShape
				|| !args.containedStencil && !args.containedShape) {
			return false;
		}

		// init arguments
		if (args.containedShape) {
			args.containedStencil = args.containedShape.getStencil();
		}

		if (args.containingShape) {
			args.containingStencil = args.containingShape.getStencil();
		}

		// if(args.containingShape) {
		// if(args.containingShape instanceof ORYX.Core.Edge) {
		// // edges cannot contain other shapes
		// return false;
		// }
		// }

		var result;

		// check containment rules
		result = args.containingStencil.roles().any((function(role) {
					var roles = this._containmentRules[role];
					if (roles) {
						return roles.any(function(role) {
									return args.containedStencil.roles()
											.member(role);
								});
					} else {
						return false;
					}
				}).bind(this));

		return result;
	},

	/** End containment rules' methods */

	/** Begin morphing rules' methods */

	/**
	 * 
	 * @param {Object}
	 *            args stencil: ORYX.Core.StencilSet.Stencil | undefined shape:
	 *            ORYX.Core.Shape | undefined
	 * 
	 * At least stencil or shape has to be specified
	 * 
	 * @return {Array} Array of stencils that the passed stencil/shape can be
	 *         transformed to (including the current stencil itself)
	 */
	morphStencils : function(args) {
		// check arguments
		if (!args.stencil && !args.shape) {
			return [];
		}

		// init arguments
		if (args.shape) {
			args.stencil = args.shape.getStencil();
		}

		var _morphStencils = [];
		args.stencil.roles().each(function(role) {
					this._cacheMorph(role).each(function(stencil) {
								_morphStencils.push(stencil);
							})
				}.bind(this));

		var baseMorphs = this.baseMorphs();
		// BaseMorphs should be in the front of the array
		_morphStencils = _morphStencils.uniq().sort(function(a, b) {
			return baseMorphs.include(a) && !baseMorphs.include(b)
					? -1
					: (baseMorphs.include(b) && !baseMorphs.include(a) ? 1 : 0)
		})
		return _morphStencils;
	},

	/**
	 * @return {Array} An array of all base morph stencils
	 */
	baseMorphs : function() {
		var _baseMorphs = [];
		this._morphingRules.each(function(pair) {
					pair.value.each(function(baseMorph) {
								_baseMorphs.push(baseMorph);
							});
				});
		return _baseMorphs;
	},

	/**
	 * Returns true if there are morphing rules defines
	 * 
	 * @return {boolean}
	 */
	containsMorphingRules : function() {
		return this._stencilSets.any(function(ss) {
					return !!ss.jsonRules().morphingRules
				});
	},

	/**
	 * 
	 * @param {Object}
	 *            args sourceStencil: ORYX.Core.StencilSet.Stencil | undefined
	 *            sourceShape: ORYX.Core.Node |undefined targetStencil:
	 *            ORYX.Core.StencilSet.Stencil | undefined targetShape:
	 *            ORYX.Core.Node |undefined
	 * 
	 * 
	 * @return {Stencil} Returns, the stencil for the connecting edge or null if
	 *         connection is not possible
	 */
	connectMorph : function(args) {
		// check arguments
		if (!args
				|| (!args.sourceShape && !args.sourceStencil
						&& !args.targetShape && !args.targetStencil)) {
			return false;
		}

		// init arguments
		if (args.sourceShape) {
			args.sourceStencil = args.sourceShape.getStencil();
		}
		if (args.targetShape) {
			args.targetStencil = args.targetShape.getStencil();
		}

		var incoming = this.incomingEdgeStencils(args);
		var outgoing = this.outgoingEdgeStencils(args);

		var edgeStencils = incoming.select(function(e) {
					return outgoing.member(e);
				}); // intersection of sets
		var baseEdgeStencils = this.baseMorphs().select(function(e) {
					return edgeStencils.member(e);
				}); // again: intersection of sets

		if (baseEdgeStencils.size() > 0)
			return baseEdgeStencils[0]; // return any of the possible base
										// morphs
		else if (edgeStencils.size() > 0)
			return edgeStencils[0]; // return any of the possible stencils

		return null; // connection not possible
	},

	/**
	 * Return true if the stencil should be located in the shape menu
	 * 
	 * @param {ORYX.Core.StencilSet.Stencil}
	 *            morph
	 * @return {Boolean} Returns true if the morphs in the morph group of the
	 *         specified morph shall be displayed in the shape menu
	 */
	showInShapeMenu : function(stencil) {
		return this._stencilSets.any(function(ss) {
					return ss.jsonRules().morphingRules.any(function(r) {
								return stencil.roles().include(ss.namespace()
										+ r.role)
										&& r.showInShapeMenu !== false;
							})
				});
	},

	preserveBounds : function(stencil) {
		return this._stencilSets.any(function(ss) {
					return ss.jsonRules().morphingRules.any(function(r) {

								return stencil.roles().include(ss.namespace()
										+ r.role)
										&& r.preserveBounds;
							})
				})
	},

	/** End morphing rules' methods */

	/** Begin layouting rules' methods */

	/**
	 * Returns a set on "in" and "out" layouting rules for a given shape
	 * 
	 * @param {Object}
	 *            shape
	 * @param {Object}
	 *            edgeShape (Optional)
	 * @return {Object} "in" and "out" with a default value of {"t":1, "r":1,
	 *         "b":1, "r":1} if not specified in the json
	 */
	getLayoutingRules : function(shape, edgeShape) {

		if (!shape || !(shape instanceof ORYX.Core.Shape)) {
			return
		}

		var layout = {
			"in" : {},
			"out" : {}
		};

		var parseValues = function(o, v) {
			if (o && o[v]) {
				["t", "r", "b", "l"].each(function(d) {
							layout[v][d] = Math.max(o[v][d], layout[v][d] || 0);
						});
			}
			if (o && o[v + "s"] instanceof Array) {
				["t", "r", "b", "l"].each(function(d) {
							var defaultRule = o[v + "s"].find(function(e) {
										return !e.edgeRole
									});
							var edgeRule;
							if (edgeShape instanceof ORYX.Core.Edge) {
								edgeRule = o[v + "s"].find(function(e) {
											return this._hasRole(edgeShape,
													e.edgeRole)
										}.bind(this));
							}
							layout[v][d] = Math
									.max(	edgeRule
													? edgeRule[d]
													: defaultRule[d],
											layout[v][d] || 0);
						}.bind(this));
			}
		}.bind(this)

		// For each role
		shape.getStencil().roles().each(function(role) {
					// check if there are layout information
					if (this._layoutRules[role]) {
						// if so, parse those information to the 'layout'
						// variable
						parseValues(this._layoutRules[role], "in");
						parseValues(this._layoutRules[role], "out");
					}
				}.bind(this));

		// Make sure, that every attribute has an value,
		// otherwise set 1
		["in", "out"].each(function(v) {
					["t", "r", "b", "l"].each(function(d) {
								layout[v][d] = layout[v][d] !== undefined
										? layout[v][d]
										: 1;
							});
				})

		return layout;
	},

	/** End layouting rules' methods */

	/** Helper methods */

	/**
	 * Checks wether a shape contains the given role or the role is equal the
	 * stencil id
	 * 
	 * @param {ORYX.Core.Shape}
	 *            shape
	 * @param {String}
	 *            role
	 */
	_hasRole : function(shape, role) {
		if (!(shape instanceof ORYX.Core.Shape) || !role) {
			return
		}
		var isRole = shape.getStencil().roles().any(function(r) {
					return r == role
				});

		return isRole
				|| shape.getStencil().id() == (shape.getStencil().namespace() + role);
	},

	/**
	 * 
	 * @param {String}
	 *            role
	 * 
	 * @return {Array} Returns an array of stencils that can act as role.
	 */
	_stencilsWithRole : function(role) {
		return this._stencils.findAll(function(stencil) {
					return (stencil.roles().member(role)) ? true : false;
				});
	},

	/**
	 * 
	 * @param {String}
	 *            role
	 * 
	 * @return {Array} Returns an array of stencils that can act as role and
	 *         have the type 'edge'.
	 */
	_edgesWithRole : function(role) {
		return this._stencils.findAll(function(stencil) {
					return (stencil.roles().member(role) && stencil.type() === "edge")
							? true
							: false;
				});
	},

	/**
	 * 
	 * @param {String}
	 *            role
	 * 
	 * @return {Array} Returns an array of stencils that can act as role and
	 *         have the type 'node'.
	 */
	_nodesWithRole : function(role) {
		return this._stencils.findAll(function(stencil) {
					return (stencil.roles().member(role) && stencil.type() === "node")
							? true
							: false;
				});
	},

	/**
	 * 
	 * @param {ORYX.Core.StencilSet.Stencil}
	 *            parent
	 * @param {ORYX.Core.StencilSet.Stencil}
	 *            child
	 * 
	 * @returns {Boolean} Returns the maximum occurrence of shapes of the
	 *          stencil's type inside the parent.
	 */
	_getMaximumOccurrence : function(parent, child) {
		var max;
		child.roles().each((function(role) {
					var cardRule = this._cardinalityRules[role];
					if (cardRule && cardRule.maximumOccurrence) {
						if (max) {
							max = Math.min(max, cardRule.maximumOccurrence);
						} else {
							max = cardRule.maximumOccurrence;
						}
					}
				}).bind(this));

		return max;
	},

	/**
	 * 
	 * @param {Object}
	 *            args sourceStencil: ORYX.Core.Node edgeStencil:
	 *            ORYX.Core.StencilSet.Stencil
	 * 
	 * @return {Boolean} Returns, the maximum number of outgoing edges of the
	 *         type specified by edgeStencil of the sourceShape.
	 */
	_getMaximumNumberOfOutgoingEdge : function(args) {
		if (!args || !args.sourceStencil || !args.edgeStencil) {
			return false;
		}

		var max;
		args.sourceStencil.roles().each((function(role) {
					var cardRule = this._cardinalityRules[role];

					if (cardRule && cardRule.outgoingEdges) {
						args.edgeStencil.roles().each(function(edgeRole) {
									var oe = cardRule.outgoingEdges[edgeRole];

									if (oe && oe.maximum) {
										if (max) {
											max = Math.min(max, oe.maximum);
										} else {
											max = oe.maximum;
										}
									}
								});
					}
				}).bind(this));

		return max;
	},

	/**
	 * 
	 * @param {Object}
	 *            args targetStencil: ORYX.Core.StencilSet.Stencil edgeStencil:
	 *            ORYX.Core.StencilSet.Stencil
	 * 
	 * @return {Boolean} Returns the maximum number of incoming edges of the
	 *         type specified by edgeStencil of the targetShape.
	 */
	_getMaximumNumberOfIncomingEdge : function(args) {
		if (!args || !args.targetStencil || !args.edgeStencil) {
			return false;
		}

		var max;
		args.targetStencil.roles().each((function(role) {
					var cardRule = this._cardinalityRules[role];
					if (cardRule && cardRule.incomingEdges) {
						args.edgeStencil.roles().each(function(edgeRole) {
									var ie = cardRule.incomingEdges[edgeRole];
									if (ie && ie.maximum) {
										if (max) {
											max = Math.min(max, ie.maximum);
										} else {
											max = ie.maximum;
										}
									}
								});
					}
				}).bind(this));

		return max;
	},

	/**
	 * 
	 * @param {ORYX.Core.StencilSet.Stencil}
	 *            edgeStencil
	 * 
	 * @return {Hash} Returns a hash map of all connection rules for
	 *         edgeStencil.
	 */
	_getConnectionRulesOfEdgeStencil : function(edgeStencil) {
		var edgeRules = new Hash();
		edgeStencil.roles().each((function(role) {
			if (this._connectionRules[role]) {
				this._connectionRules[role].each(function(cr) {
							if (edgeRules[cr.key]) {
								edgeRules[cr.key] = edgeRules[cr.key]
										.concat(cr.value);
							} else {
								edgeRules[cr.key] = cr.value;
							}
						});
			}
		}).bind(this));

		return edgeRules;
	},

	_isRoleOfOtherNamespace : function(role) {
		return (role.indexOf("#") > 0);
	},

	toString : function() {
		return "Rules";
	}
}
ORYX.Core.StencilSet.Rules = Clazz.extend(ORYX.Core.StencilSet.Rules);
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespace
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.StencilSet) {
	ORYX.Core.StencilSet = {};
}

/**
 * This class represents a stencil set. It offers methods for accessing the
 * attributes of the stencil set description JSON file and the stencil set's
 * stencils.
 */
ORYX.Core.StencilSet.StencilSet = Clazz.extend({

	/**
	 * Constructor
	 * 
	 * @param source
	 *            {URL} A reference to the stencil set specification.
	 * 
	 */
	construct : function(source, modelMetaData, editorId) {
		arguments.callee.$.construct.apply(this, arguments);

		if (!source) {
			throw "ORYX.Core.StencilSet.StencilSet(construct): Parameter 'source' is not defined.";
		}

		if (source.endsWith("/")) {
			source = source.substr(0, source.length - 1);
		}

		this._extensions = new Hash();

		this._source = source;
		this._baseUrl = source.substring(0, source.lastIndexOf("/") + 1);

		this._jsonObject = {};

		this._stencils = new Hash();
		this._availableStencils = new Hash();

		if (ORYX.CONFIG.BACKEND_SWITCH) {
			this._baseUrl = "editor/stencilsets/bpmn2.0/";
			this._source = "stencilsets/bpmn2.0/bpmn2.0.json";

			new Ajax.Request(ACTIVITI.CONFIG.contextRoot
							+ '/editor/stencilset?version=' + Date.now(), {
						asynchronous : false,
						method : 'get',
						onSuccess : this._init.bind(this),
						onFailure : this._cancelInit.bind(this)
					});

		} else {
			new Ajax.Request(source, {
						asynchronous : false,
						method : 'get',
						onSuccess : this._init.bind(this),
						onFailure : this._cancelInit.bind(this)
					});
		}

		if (this.errornous)
			throw "Loading stencil set " + source + " failed.";
	},

	/**
	 * Finds a root stencil in this stencil set. There may be many of these. If
	 * there are, the first one found will be used. In Firefox, this is the
	 * topmost definition in the stencil set description file.
	 */
	findRootStencilName : function() {

		// find any stencil that may be root.
		var rootStencil = this._stencils.values().find(function(stencil) {
					return stencil._jsonStencil.mayBeRoot
				});

		// if there is none, just guess the first.
		if (!rootStencil) {
			ORYX.Log
					.warn("Did not find any stencil that may be root. Taking a guess.");
			rootStencil = this._stencils.values()[0];
		}

		// return its id.
		return rootStencil.id();
	},

	/**
	 * @param {ORYX.Core.StencilSet.StencilSet}
	 *            stencilSet
	 * @return {Boolean} True, if stencil set has the same namespace.
	 */
	equals : function(stencilSet) {
		return (this.namespace() === stencilSet.namespace());
	},

	/**
	 * 
	 * @param {Oryx.Core.StencilSet.Stencil}
	 *            rootStencil If rootStencil is defined, it only returns
	 *            stencils that could be (in)direct child of that stencil.
	 */
	stencils : function(rootStencil, rules, sortByGroup) {
		if (rootStencil && rules) {
			var stencils = this._availableStencils.values();
			var containers = [rootStencil];
			var checkedContainers = [];

			var result = [];

			while (containers.size() > 0) {
				var container = containers.pop();
				checkedContainers.push(container);
				var children = stencils.findAll(function(stencil) {
							var args = {
								containingStencil : container,
								containedStencil : stencil
							};
							return rules.canContain(args);
						});
				for (var i = 0; i < children.size(); i++) {
					if (!checkedContainers.member(children[i])) {
						containers.push(children[i]);
					}
				}
				result = result.concat(children).uniq();
			}

			// Sort the result to the origin order
			result = result.sortBy(function(stencil) {
						return stencils.indexOf(stencil);
					});

			if (sortByGroup) {
				result = result.sortBy(function(stencil) {
							return stencil.groups().first();
						});
			}

			var edges = stencils.findAll(function(stencil) {
						return stencil.type() == "edge";
					});
			result = result.concat(edges);

			return result;

		} else {
			if (sortByGroup) {
				return this._availableStencils.values().sortBy(
						function(stencil) {
							return stencil.groups().first();
						});
			} else {
				return this._availableStencils.values();
			}
		}
	},

	nodes : function() {
		return this._availableStencils.values().findAll(function(stencil) {
					return (stencil.type() === 'node')
				});
	},

	edges : function() {
		return this._availableStencils.values().findAll(function(stencil) {
					return (stencil.type() === 'edge')
				});
	},

	stencil : function(id) {
		return this._stencils[id];
	},

	title : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonObject, "title");
	},

	description : function() {
		return ORYX.Core.StencilSet.getTranslation(this._jsonObject,
				"description");
	},

	namespace : function() {
		return this._jsonObject ? this._jsonObject.namespace : null;
	},

	jsonRules : function() {
		return this._jsonObject ? this._jsonObject.rules : null;
	},

	source : function() {
		return this._source;
	},

	extensions : function() {
		return this._extensions;
	},

	addExtension : function(url) {

		new Ajax.Request(url, {
			method : 'GET',
			asynchronous : false,
			onSuccess : (function(transport) {
				this.addExtensionDirectly(transport.responseText);
			}).bind(this),
			onFailure : (function(transport) {
				ORYX.Log
						.debug("Loading stencil set extension file failed. The request returned an error."
								+ transport);
			}).bind(this),
			onException : (function(transport) {
				ORYX.Log
						.debug("Loading stencil set extension file failed. The request returned an error."
								+ transport);
			}).bind(this)

		});
	},

	addExtensionDirectly : function(str) {

		try {
			eval("var jsonExtension = " + str);

			if (!(jsonExtension["extends"].endsWith("#")))
				jsonExtension["extends"] += "#";

			if (jsonExtension["extends"] == this.namespace()) {
				this._extensions[jsonExtension.namespace] = jsonExtension;

				var defaultPosition = this._stencils.keys().size();
				// load new stencils
				if (jsonExtension.stencils) {
					$A(jsonExtension.stencils).each(function(stencil) {
						defaultPosition++;
						var oStencil = new ORYX.Core.StencilSet.Stencil(
								stencil, this.namespace(), this._baseUrl, this,
								undefined, defaultPosition);
						this._stencils[oStencil.id()] = oStencil;
						this._availableStencils[oStencil.id()] = oStencil;
					}.bind(this));
				}

				// load additional properties
				if (jsonExtension.properties) {
					var stencils = this._stencils.values();

					stencils.each(function(stencil) {
						var roles = stencil.roles();

						jsonExtension.properties.each(function(prop) {
							prop.roles.any(function(role) {
								role = jsonExtension["extends"] + role;
								if (roles.member(role)) {
									prop.properties.each(function(property) {
												stencil
														.addProperty(
																property,
																jsonExtension.namespace);
											});

									return true;
								} else
									return false;
							})
						})
					}.bind(this));
				}

				// remove stencil properties
				if (jsonExtension.removeproperties) {
					jsonExtension.removeproperties.each(function(remprop) {
								var stencil = this
										.stencil(jsonExtension["extends"]
												+ remprop.stencil);
								if (stencil) {
									remprop.properties.each(function(propId) {
												stencil.removeProperty(propId);
											});
								}
							}.bind(this));
				}

				// remove stencils
				if (jsonExtension.removestencils) {
					$A(jsonExtension.removestencils).each(function(remstencil) {
						delete this._availableStencils[jsonExtension["extends"]
								+ remstencil];
					}.bind(this));
				}
			}
		} catch (e) {
			ORYX.Log
					.debug("StencilSet.addExtension: Something went wrong when initialising the stencil set extension. "
							+ e);
		}
	},

	removeExtension : function(namespace) {
		var jsonExtension = this._extensions[namespace];
		if (jsonExtension) {

			// unload extension's stencils
			if (jsonExtension.stencils) {
				$A(jsonExtension.stencils).each(function(stencil) {
					var oStencil = new ORYX.Core.StencilSet.Stencil(stencil,
							this.namespace(), this._baseUrl, this);
					delete this._stencils[oStencil.id()]; // maybe not ??
					delete this._availableStencils[oStencil.id()];
				}.bind(this));
			}

			// unload extension's properties
			if (jsonExtension.properties) {
				var stencils = this._stencils.values();

				stencils.each(function(stencil) {
					var roles = stencil.roles();

					jsonExtension.properties.each(function(prop) {
						prop.roles.any(function(role) {
							role = jsonExtension["extends"] + role;
							if (roles.member(role)) {
								prop.properties.each(function(property) {
											stencil.removeProperty(property.id);
										});

								return true;
							} else
								return false;
						})
					})
				}.bind(this));
			}

			// restore removed stencil properties
			if (jsonExtension.removeproperties) {
				jsonExtension.removeproperties.each(function(remprop) {
					var stencil = this.stencil(jsonExtension["extends"]
							+ remprop.stencil);
					if (stencil) {
						var stencilJson = $A(this._jsonObject.stencils).find(
								function(s) {
									return s.id == stencil.id()
								});
						remprop.properties.each(function(propId) {
							var propertyJson = $A(stencilJson.properties).find(
									function(p) {
										return p.id == propId
									});
							stencil.addProperty(propertyJson, this.namespace());
						}.bind(this));
					}
				}.bind(this));
			}

			// restore removed stencils
			if (jsonExtension.removestencils) {
				$A(jsonExtension.removestencils).each(function(remstencil) {
							var sId = jsonExtension["extends"] + remstencil;
							this._availableStencils[sId] = this._stencils[sId];
						}.bind(this));
			}
		}
		delete this._extensions[namespace];
	},

	__handleStencilset : function(response) {

		try {
			// using eval instead of prototype's parsing,
			// since there are functions in this JSON.
			eval("this._jsonObject =" + response.responseText);
		} catch (e) {
			throw "Stenciset corrupt: " + e;
		}

		// assert it was parsed.
		if (!this._jsonObject) {
			throw "Error evaluating stencilset. It may be corrupt.";
		}

		with (this._jsonObject) {

			// assert there is a namespace.
			if (!namespace || namespace === "")
				throw "Namespace definition missing in stencilset.";

			if (!(stencils instanceof Array))
				throw "Stencilset corrupt.";

			// assert namespace ends with '#'.
			if (!namespace.endsWith("#"))
				namespace = namespace + "#";

			// assert title and description are strings.
			if (!title)
				title = "";
			if (!description)
				description = "";
		}
	},

	/**
	 * This method is called when the HTTP request to get the requested stencil
	 * set succeeds. The response is supposed to be a JSON representation
	 * according to the stencil set specification.
	 * 
	 * @param {Object}
	 *            response The JSON representation according to the stencil set
	 *            specification.
	 */
	_init : function(response) {

		// init and check consistency.
		this.__handleStencilset(response);

		var pps = new Hash();

		// init property packages
		if (this._jsonObject.propertyPackages) {
			$A(this._jsonObject.propertyPackages).each((function(pp) {
						pps[pp.name] = pp.properties;
					}).bind(this));
		}

		var defaultPosition = 0;

		// init each stencil
		$A(this._jsonObject.stencils).each((function(stencil) {
			defaultPosition++;

			// instantiate normally.
			var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this
							.namespace(), this._baseUrl, this, pps,
					defaultPosition);
			this._stencils[oStencil.id()] = oStencil;
			this._availableStencils[oStencil.id()] = oStencil;

		}).bind(this));
	},

	_cancelInit : function(response) {
		this.errornous = true;
	},

	toString : function() {
		return "StencilSet " + this.title() + " (" + this.namespace() + ")";
	}
});
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespace
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.StencilSet) {
	ORYX.Core.StencilSet = {};
}

/**
 * Class StencilSets uses Prototpye 1.5.0 uses Inheritance
 * 
 * Singleton
 */
// storage for loaded stencil sets by namespace
ORYX.Core.StencilSet._stencilSetsByNamespace = new Hash();

// storage for stencil sets by url
ORYX.Core.StencilSet._stencilSetsByUrl = new Hash();

// storage for stencil set namespaces by editor instances
ORYX.Core.StencilSet._StencilSetNSByEditorInstance = new Hash();

// storage for rules by editor instances
ORYX.Core.StencilSet._rulesByEditorInstance = new Hash();

/**
 * 
 * @param {String}
 *            editorId
 * 
 * @return {Hash} Returns a hash map with all stencil sets that are loaded by
 *         the editor with the editorId.
 */
ORYX.Core.StencilSet.stencilSets = function(editorId) {
	var stencilSetNSs = ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId];
	var stencilSets = new Hash();
	if (stencilSetNSs) {
		stencilSetNSs.each(function(stencilSetNS) {
					var stencilSet = ORYX.Core.StencilSet
							.stencilSet(stencilSetNS)
					stencilSets[stencilSet.namespace()] = stencilSet;
				});
	}
	return stencilSets;
};

/**
 * 
 * @param {String}
 *            namespace
 * 
 * @return {ORYX.Core.StencilSet.StencilSet} Returns the stencil set with the
 *         specified namespace.
 * 
 * The method can handle namespace strings like
 * http://www.example.org/stencilset http://www.example.org/stencilset#
 * http://www.example.org/stencilset#ANode
 */
ORYX.Core.StencilSet.stencilSet = function(namespace) {
	ORYX.Log.trace("Getting stencil set %0", namespace);
	var splitted = namespace.split("#", 1);
	if (splitted.length === 1) {
		ORYX.Log.trace("Getting stencil set %0", splitted[0]);
		return ORYX.Core.StencilSet._stencilSetsByNamespace[splitted[0] + "#"];
	} else {
		return undefined;
	}
};

/**
 * 
 * @param {String}
 *            id
 * 
 * @return {ORYX.Core.StencilSet.Stencil} Returns the stencil specified by the
 *         id.
 * 
 * The id must be unique and contains the namespace of the stencil's stencil
 * set. e.g. http://www.example.org/stencilset#ANode
 */
ORYX.Core.StencilSet.stencil = function(id) {
	ORYX.Log.trace("Getting stencil for %0", id);
	var ss = ORYX.Core.StencilSet.stencilSet(id);
	if (ss) {
		return ss.stencil(id);
	} else {

		ORYX.Log.trace("Cannot fild stencil for %0", id);
		return undefined;
	}
};

/**
 * 
 * @param {String}
 *            editorId
 * 
 * @return {ORYX.Core.StencilSet.Rules} Returns the rules object for the editor
 *         specified by its editor id.
 */
ORYX.Core.StencilSet.rules = function(editorId) {
	if (!ORYX.Core.StencilSet._rulesByEditorInstance[editorId]) {
		ORYX.Core.StencilSet._rulesByEditorInstance[editorId] = new ORYX.Core.StencilSet.Rules();
	}
	return ORYX.Core.StencilSet._rulesByEditorInstance[editorId];
};

/**
 * 
 * @param {String}
 *            url
 * @param {String}
 *            editorId
 * 
 * Loads a stencil set from url, if it is not already loaded. It also stores
 * which editor instance loads the stencil set and initializes the Rules object
 * for the editor instance.
 */
ORYX.Core.StencilSet.loadStencilSet = function(url, modelMetaData, editorId) {

	// Alfresco: disable cache, because stencil sets are now flexible

	// var stencilSet = ORYX.Core.StencilSet._stencilSetsByUrl[url];

	// if(!stencilSet) {
	// load stencil set
	stencilSet = new ORYX.Core.StencilSet.StencilSet(url, modelMetaData,
			editorId);

	// store stencil set
	ORYX.Core.StencilSet._stencilSetsByNamespace[stencilSet.namespace()] = stencilSet;

	// store stencil set by url
	ORYX.Core.StencilSet._stencilSetsByUrl[url] = stencilSet;
	// }

	var namespace = stencilSet.namespace();

	// store which editorInstance loads the stencil set
	if (ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId]) {
		ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId]
				.push(namespace);
	} else {
		ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId] = [namespace];
	}

	// store the rules for the editor instance
	if (ORYX.Core.StencilSet._rulesByEditorInstance[editorId]) {
		ORYX.Core.StencilSet._rulesByEditorInstance[editorId]
				.initializeRules(stencilSet);
	} else {
		var rules = new ORYX.Core.StencilSet.Rules();
		rules.initializeRules(stencilSet);
		ORYX.Core.StencilSet._rulesByEditorInstance[editorId] = rules;
	}
};

/**
 * Returns the translation of an attribute in jsonObject specified by its name
 * according to navigator.language
 */
ORYX.Core.StencilSet.getTranslation = function(jsonObject, name) {
	var lang = ORYX.I18N.Language.toLowerCase();

	var result = jsonObject[name + "_" + lang];

	if (result)
		return result;

	result = jsonObject[name + "_" + lang.substr(0, 2)];

	if (result)
		return result;

	return jsonObject[name];
};
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}

/**
 * @classDescription With Bounds you can set and get position and size of
 *                   UIObjects.
 */
ORYX.Core.Command = Clazz.extend({

			/**
			 * Constructor
			 */
			construct : function() {

			},

			execute : function() {
				throw "Command.execute() has to be implemented!"
			},

			rollback : function() {
				throw "Command.rollback() has to be implemented!"
			}

		});/*
			 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
			 * License rights for this program may be obtained from Alfresco
			 * Software, Ltd. pursuant to a written agreement and any use of
			 * this program without such an agreement is prohibited.
			 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}

/**
 * @classDescription With Bounds you can set and get position and size of
 *                   UIObjects.
 */
ORYX.Core.Bounds = {

	/**
	 * Constructor
	 */
	construct : function() {
		this._changedCallbacks = []; // register a callback with
										// changedCallacks.push(this.method.bind(this));
		this.a = {};
		this.b = {};
		this.set.apply(this, arguments);
		this.suspendChange = false;
		this.changedWhileSuspend = false;
	},

	/**
	 * Calls all registered callbacks.
	 */
	_changed : function(sizeChanged) {
		if (!this.suspendChange) {
			this._changedCallbacks.each(function(callback) {
						callback(this, sizeChanged);
					}.bind(this));
			this.changedWhileSuspend = false;
		} else
			this.changedWhileSuspend = true;
	},

	/**
	 * Registers a callback that is called, if the bounds changes.
	 * 
	 * @param callback
	 *            {Function} The callback function.
	 */
	registerCallback : function(callback) {
		if (!this._changedCallbacks.member(callback)) {
			this._changedCallbacks.push(callback);
		}
	},

	/**
	 * Unregisters a callback.
	 * 
	 * @param callback
	 *            {Function} The callback function.
	 */
	unregisterCallback : function(callback) {
		this._changedCallbacks = this._changedCallbacks.without(callback);
	},

	/**
	 * Sets position and size of the shape dependent of four coordinates
	 * (set(ax, ay, bx, by);), two points (set({x: ax, y: ay}, {x: bx, y: by});)
	 * or one bound (set({a: {x: ax, y: ay}, b: {x: bx, y: by}});).
	 */
	set : function() {

		var changed = false;

		switch (arguments.length) {

			case 1 :
				if (this.a.x !== arguments[0].a.x) {
					changed = true;
					this.a.x = arguments[0].a.x;
				}
				if (this.a.y !== arguments[0].a.y) {
					changed = true;
					this.a.y = arguments[0].a.y;
				}
				if (this.b.x !== arguments[0].b.x) {
					changed = true;
					this.b.x = arguments[0].b.x;
				}
				if (this.b.y !== arguments[0].b.y) {
					changed = true;
					this.b.y = arguments[0].b.y;
				}
				break;

			case 2 :
				var ax = Math.min(arguments[0].x, arguments[1].x);
				var ay = Math.min(arguments[0].y, arguments[1].y);
				var bx = Math.max(arguments[0].x, arguments[1].x);
				var by = Math.max(arguments[0].y, arguments[1].y);
				if (this.a.x !== ax) {
					changed = true;
					this.a.x = ax;
				}
				if (this.a.y !== ay) {
					changed = true;
					this.a.y = ay;
				}
				if (this.b.x !== bx) {
					changed = true;
					this.b.x = bx;
				}
				if (this.b.y !== by) {
					changed = true;
					this.b.y = by;
				}
				break;

			case 4 :
				var ax = Math.min(arguments[0], arguments[2]);
				var ay = Math.min(arguments[1], arguments[3]);
				var bx = Math.max(arguments[0], arguments[2]);
				var by = Math.max(arguments[1], arguments[3]);
				if (this.a.x !== ax) {
					changed = true;
					this.a.x = ax;
				}
				if (this.a.y !== ay) {
					changed = true;
					this.a.y = ay;
				}
				if (this.b.x !== bx) {
					changed = true;
					this.b.x = bx;
				}
				if (this.b.y !== by) {
					changed = true;
					this.b.y = by;
				}
				break;
		}

		if (changed) {
			this._changed(true);
		}
	},

	/**
	 * Moves the bounds so that the point p will be the new upper left corner.
	 * 
	 * @param {Point}
	 *            p or
	 * @param {Number}
	 *            x
	 * @param {Number}
	 *            y
	 */
	moveTo : function() {

		var currentPosition = this.upperLeft();
		switch (arguments.length) {
			case 1 :
				this.moveBy({
							x : arguments[0].x - currentPosition.x,
							y : arguments[0].y - currentPosition.y
						});
				break;
			case 2 :
				this.moveBy({
							x : arguments[0] - currentPosition.x,
							y : arguments[1] - currentPosition.y
						});
				break;
			default :
				// TODO error
		}

	},

	/**
	 * Moves the bounds relatively by p.
	 * 
	 * @param {Point}
	 *            p or
	 * @param {Number}
	 *            x
	 * @param {Number}
	 *            y
	 * 
	 */
	moveBy : function() {
		var changed = false;

		switch (arguments.length) {
			case 1 :
				var p = arguments[0];
				if (p.x !== 0 || p.y !== 0) {
					changed = true;
					this.a.x += p.x;
					this.b.x += p.x;
					this.a.y += p.y;
					this.b.y += p.y;
				}
				break;
			case 2 :
				var x = arguments[0];
				var y = arguments[1];
				if (x !== 0 || y !== 0) {
					changed = true;
					this.a.x += x;
					this.b.x += x;
					this.a.y += y;
					this.b.y += y;
				}
				break;
			default :
				// TODO error
		}

		if (changed) {
			this._changed();
		}
	},

	/***************************************************************************
	 * Includes the bounds b into the current bounds.
	 * 
	 * @param {Bounds}
	 *            b
	 */
	include : function(b) {

		if ((this.a.x === undefined) && (this.a.y === undefined)
				&& (this.b.x === undefined) && (this.b.y === undefined)) {
			return b;
		};

		var cx = Math.min(this.a.x, b.a.x);
		var cy = Math.min(this.a.y, b.a.y);

		var dx = Math.max(this.b.x, b.b.x);
		var dy = Math.max(this.b.y, b.b.y);

		this.set(cx, cy, dx, dy);
	},

	/**
	 * Relatively extends the bounds by p.
	 * 
	 * @param {Point}
	 *            p
	 */
	extend : function(p) {

		if (p.x !== 0 || p.y !== 0) {
			// this is over cross for the case that a and b have same
			// coordinates.
			// ((this.a.x > this.b.x) ? this.a : this.b).x += p.x;
			// ((this.b.y > this.a.y) ? this.b : this.a).y += p.y;
			this.b.x += p.x;
			this.b.y += p.y;

			this._changed(true);
		}
	},

	/**
	 * Widens the scope of the bounds by x.
	 * 
	 * @param {Number}
	 *            x
	 */
	widen : function(x) {
		if (x !== 0) {
			this.suspendChange = true;
			this.moveBy({
						x : -x,
						y : -x
					});
			this.extend({
						x : 2 * x,
						y : 2 * x
					});
			this.suspendChange = false;
			if (this.changedWhileSuspend) {
				this._changed(true);
			}
		}
	},

	/**
	 * Returns the upper left corner's point regardless of the bound delimiter
	 * points.
	 */
	upperLeft : function() {
		var result = {};
		result.x = this.a.x;
		result.y = this.a.y;
		return result;
	},

	/**
	 * Returns the lower Right left corner's point regardless of the bound
	 * delimiter points.
	 */
	lowerRight : function() {
		var result = {};
		result.x = this.b.x;
		result.y = this.b.y;
		return result;
	},

	/**
	 * @return {Number} Width of bounds.
	 */
	width : function() {
		return this.b.x - this.a.x;
	},

	/**
	 * @return {Number} Height of bounds.
	 */
	height : function() {
		return this.b.y - this.a.y;
	},

	/**
	 * @return {Point} The center point of this bounds.
	 */
	center : function() {
		var center = {};
		center.x = (this.a.x + this.b.x) / 2.0;
		center.y = (this.a.y + this.b.y) / 2.0;
		return center;
	},

	/**
	 * @return {Point} The center point of this bounds relative to upperLeft.
	 */
	midPoint : function() {

		var midpoint = {};
		midpoint.x = (this.b.x - this.a.x) / 2.0;
		midpoint.y = (this.b.y - this.a.y) / 2.0;
		return midpoint;
	},

	/**
	 * Moves the center point of this bounds to the new position.
	 * 
	 * @param p
	 *            {Point} or
	 * @param x
	 *            {Number}
	 * @param y
	 *            {Number}
	 */
	centerMoveTo : function() {
		var currentPosition = this.center();

		switch (arguments.length) {

			case 1 :
				this.moveBy(arguments[0].x - currentPosition.x, arguments[0].y
								- currentPosition.y);
				break;

			case 2 :
				this.moveBy(arguments[0] - currentPosition.x, arguments[1]
								- currentPosition.y);
				break;
		}
	},

	isIncluded : function(point, offset) {

		var pointX, pointY, offset;

		// Get the the two Points
		switch (arguments.length) {
			case 1 :
				pointX = arguments[0].x;
				pointY = arguments[0].y;
				offset = 0;

				break;
			case 2 :
				if (arguments[0].x && arguments[0].y) {
					pointX = arguments[0].x;
					pointY = arguments[0].y;
					offset = Math.abs(arguments[1]);
				} else {
					pointX = arguments[0];
					pointY = arguments[1];
					offset = 0;
				}
				break;
			case 3 :
				pointX = arguments[0];
				pointY = arguments[1];
				offset = Math.abs(arguments[2]);
				break;
			default :
				throw "isIncluded needs one, two or three arguments";
		}

		var ul = this.upperLeft();
		var lr = this.lowerRight();

		if (pointX >= ul.x - offset && pointX <= lr.x + offset
				&& pointY >= ul.y - offset && pointY <= lr.y + offset)
			return true;
		else
			return false;
	},

	/**
	 * @return {Bounds} A copy of this bounds.
	 */
	clone : function() {

		// Returns a new bounds object without the callback
		// references of the original bounds
		return new ORYX.Core.Bounds(this);
	},

	toString : function() {

		return "( " + this.a.x + " | " + this.a.y + " )/( " + this.b.x + " | "
				+ this.b.y + " )";
	},

	serializeForERDF : function() {

		return this.a.x + "," + this.a.y + "," + this.b.x + "," + this.b.y;
	}
};

ORYX.Core.Bounds = Clazz.extend(ORYX.Core.Bounds);/*
													 * Copyright 2005-2014
													 * Alfresco Software, Ltd.
													 * All rights reserved.
													 * License rights for this
													 * program may be obtained
													 * from Alfresco Software,
													 * Ltd. pursuant to a
													 * written agreement and any
													 * use of this program
													 * without such an agreement
													 * is prohibited.
													 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}

/**
 * @classDescription Abstract base class for all objects that have a graphical
 *                   representation within the editor.
 * @extends Clazz
 */
ORYX.Core.UIObject = {
	/**
	 * Constructor of the UIObject class.
	 */
	construct : function(options) {

		this.isChanged = true; // Flag, if UIObject has been changed since last
								// update.
		this.isResized = true;
		this.isVisible = true; // Flag, if UIObject's display attribute is set
								// to 'inherit' or 'none'
		this.isSelectable = false; // Flag, if UIObject is selectable.
		this.isResizable = false; // Flag, if UIObject is resizable.
		this.isMovable = false; // Flag, if UIObject is movable.

		this.id = ORYX.Editor.provideId(); // get unique id
		this.parent = undefined; // parent is defined, if this object is
									// added to another uiObject.
		this.node = undefined; // this is a reference to the SVG
								// representation, either locally or in DOM.
		this.children = []; // array for all add uiObjects

		this.bounds = new ORYX.Core.Bounds(); // bounds with undefined values

		this._changedCallback = this._changed.bind(this); // callback
															// reference for
															// calling _changed
		this.bounds.registerCallback(this._changedCallback); // set callback
																// in bounds

		if (options && options.eventHandlerCallback) {
			this.eventHandlerCallback = options.eventHandlerCallback;
		}
	},

	/**
	 * Sets isChanged flag to true. Callback for the bounds object.
	 */
	_changed : function(bounds, isResized) {
		this.isChanged = true;
		if (this.bounds == bounds)
			this.isResized = isResized || this.isResized;
	},

	/**
	 * If something changed, this method calls the refresh method that must be
	 * implemented by subclasses.
	 */
	update : function() {
		if (this.isChanged) {
			this.refresh();
			this.isChanged = false;

			// call update of all children
			this.children.each(function(value) {
						value.update();
					});
		}
	},

	/**
	 * Is called in update method, if isChanged is set to true. Sub classes
	 * should call the super class method.
	 */
	refresh : function() {

	},

	/**
	 * @return {Array} Array of all child UIObjects.
	 */
	getChildren : function() {
		return this.children.clone();
	},

	/**
	 * @return {Array} Array of all parent UIObjects.
	 */
	getParents : function() {
		var parents = [];
		var parent = this.parent;
		while (parent) {
			parents.push(parent);
			parent = parent.parent;
		}
		return parents;
	},

	/**
	 * Returns TRUE if the given parent is one of the UIObjects parents or the
	 * UIObject themselves, otherwise FALSE.
	 * 
	 * @param {UIObject}
	 *            parent
	 * @return {Boolean}
	 */
	isParent : function(parent) {
		var cparent = this;
		while (cparent) {
			if (cparent === parent) {
				return true;
			}
			cparent = cparent.parent;
		}
		return false;
	},

	/**
	 * @return {String} Id of this UIObject
	 */
	getId : function() {
		return this.id;
	},

	/**
	 * Method for accessing child uiObjects by id.
	 * 
	 * @param {String}
	 *            id
	 * @param {Boolean}
	 *            deep
	 * 
	 * @return {UIObject} If found, it returns the UIObject with id.
	 */
	getChildById : function(id, deep) {
		return this.children.find(function(uiObj) {
					if (uiObj.getId() === id) {
						return uiObj;
					} else {
						if (deep) {
							var obj = uiObj.getChildById(id, deep);
							if (obj) {
								return obj;
							}
						}
					}
				});
	},

	/**
	 * Adds an UIObject to this UIObject and sets the parent of the added
	 * UIObject. It is also added to the SVG representation of this UIObject.
	 * 
	 * @param {UIObject}
	 *            uiObject
	 */
	add : function(uiObject) {
		// add uiObject, if it is not already a child of this object
		if (!(this.children.member(uiObject))) {
			// if uiObject is child of another parent, remove it from that
			// parent.
			if (uiObject.parent) {
				uiObject.remove(uiObject);
			}

			// add uiObject to children
			this.children.push(uiObject);

			// set parent reference
			uiObject.parent = this;

			// add uiObject.node to this.node
			uiObject.node = this.node.appendChild(uiObject.node);

			// register callback to get informed, if child is changed
			uiObject.bounds.registerCallback(this._changedCallback);

			// uiObject.update();
		} else {
			ORYX.Log
					.info("add: ORYX.Core.UIObject is already a child of this object.");
		}
	},

	/**
	 * Removes UIObject from this UIObject. The SVG representation will also be
	 * removed from this UIObject's SVG representation.
	 * 
	 * @param {UIObject}
	 *            uiObject
	 */
	remove : function(uiObject) {
		// if uiObject is a child of this object, remove it.
		if (this.children.member(uiObject)) {
			// remove uiObject from children
			this.children = this._uiObjects.without(uiObject);

			// delete parent reference of uiObject
			uiObject.parent = undefined;

			// delete uiObject.node from this.node
			uiObject.node = this.node.removeChild(uiObject.node);

			// unregister callback to get informed, if child is changed
			uiObject.bounds.unregisterCallback(this._changedCallback);
		} else {
			ORYX.Log
					.info("remove: ORYX.Core.UIObject is not a child of this object.");
		}

	},

	/**
	 * Calculates absolute bounds of this UIObject.
	 */
	absoluteBounds : function() {
		if (this.parent) {
			var absUL = this.absoluteXY();
			return new ORYX.Core.Bounds(absUL.x, absUL.y, absUL.x
							+ this.bounds.width(), absUL.y
							+ this.bounds.height());
		} else {
			return this.bounds.clone();
		}
	},

	/**
	 * @return {Point} The absolute position of this UIObject.
	 */
	absoluteXY : function() {
		if (this.parent) {
			var pXY = this.parent.absoluteXY();
			var result = {};
			result.x = pXY.x + this.bounds.upperLeft().x;
			result.y = pXY.y + this.bounds.upperLeft().y;
			return result;
		} else {
			var result = {};
			result.x = this.bounds.upperLeft().x;
			result.y = this.bounds.upperLeft().y;
			return result;
		}
	},

	/**
	 * @return {Point} The absolute position from the Center of this UIObject.
	 */
	absoluteCenterXY : function() {
		if (this.parent) {
			var pXY = this.parent.absoluteXY();
			var result = {};
			result.x = pXY.x + this.bounds.center().x;
			result.y = pXY.y + this.bounds.center().y;
			return result;

		} else {
			var result = {};
			result.x = this.bounds.center().x;
			result.y = this.bounds.center().y;
			return result;
		}
	},

	/**
	 * Hides this UIObject and all its children.
	 */
	hide : function() {
		this.node.setAttributeNS(null, 'display', 'none');
		this.isVisible = false;
		this.children.each(function(uiObj) {
					uiObj.hide();
				});
	},

	/**
	 * Enables visibility of this UIObject and all its children.
	 */
	show : function() {
		this.node.setAttributeNS(null, 'display', 'inherit');
		this.isVisible = true;
		this.children.each(function(uiObj) {
					uiObj.show();
				});
	},

	addEventHandlers : function(node) {

		node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this._delegateEvent
						.bind(this), false);
		node.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this._delegateEvent
						.bind(this), false);
		node.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this._delegateEvent
						.bind(this), false);
		node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, this._delegateEvent
						.bind(this), false);
		node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOUT, this._delegateEvent
						.bind(this), false);
		node.addEventListener('click', this._delegateEvent.bind(this), false);
		node.addEventListener(ORYX.CONFIG.EVENT_DBLCLICK, this._delegateEvent
						.bind(this), false);

	},

	_delegateEvent : function(event) {
		if (this.eventHandlerCallback) {
			this.eventHandlerCallback(event, this);
		}
	},

	toString : function() {
		return "UIObject " + this.id
	}
};
ORYX.Core.UIObject = Clazz.extend(ORYX.Core.UIObject);/*
														 * Copyright 2005-2014
														 * Alfresco Software,
														 * Ltd. All rights
														 * reserved. License
														 * rights for this
														 * program may be
														 * obtained from
														 * Alfresco Software,
														 * Ltd. pursuant to a
														 * written agreement and
														 * any use of this
														 * program without such
														 * an agreement is
														 * prohibited.
														 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}

/**
 * Top Level uiobject.
 * 
 * @class ORYX.Core.AbstractShape
 * @extends ORYX.Core.UIObject
 */
ORYX.Core.AbstractShape = ORYX.Core.UIObject.extend(
/** @lends ORYX.Core.AbstractShape.prototype */
		{

	/**
	 * Constructor
	 */
	construct : function(options, stencil, facade) {

		arguments.callee.$.construct.apply(this, arguments);

		this.resourceId = ORYX.Editor.provideId(); // Id of resource in DOM

		// stencil reference
		this._stencil = stencil;
		// if the stencil defines a super stencil that should be used for its
		// instances, set it.
		if (this._stencil._jsonStencil.superId) {
			stencilId = this._stencil.id()
			superStencilId = stencilId.substring(0, stencilId.indexOf("#") + 1)
					+ stencil._jsonStencil.superId;
			stencilSet = this._stencil.stencilSet();
			this._stencil = stencilSet.stencil(superStencilId);
		}

		// Hash map for all properties. Only stores the values of the
		// properties.
		this.properties = new Hash();
		this.propertiesChanged = new Hash();

		// List of properties which are not included in the stencilset,
		// but which gets (de)serialized
		this.hiddenProperties = new Hash();

		// Initialization of property map and initial value.
		this._stencil.properties().each((function(property) {
					var key = property.prefix() + "-" + property.id();
					this.properties[key] = property.value();
					this.propertiesChanged[key] = true;
				}).bind(this));

		// if super stencil was defined, also regard stencil's properties:
		if (stencil._jsonStencil.superId) {
			stencil.properties().each((function(property) {
				var key = property.prefix() + "-" + property.id();
				var value = property.value();
				var oldValue = this.properties[key];
				this.properties[key] = value;
				this.propertiesChanged[key] = true;

				// Raise an event, to show that the property has changed
				// required for plugins like processLink.js
				// window.setTimeout( function(){

				this._delegateEvent({
							type : ORYX.CONFIG.EVENT_PROPERTY_CHANGED,
							name : key,
							value : value,
							oldValue : oldValue
						});

					// }.bind(this), 10)

				}).bind(this));
		}

	},

	layout : function() {

	},

	/**
	 * Returns the stencil object specifiing the type of the shape.
	 */
	getStencil : function() {
		return this._stencil;
	},

	/**
	 * 
	 * @param {Object}
	 *            resourceId
	 */
	getChildShapeByResourceId : function(resourceId) {

		resourceId = ERDF.__stripHashes(resourceId);

		return this.getChildShapes(true).find(function(shape) {
					return shape.resourceId == resourceId
				});
	},
	/**
	 * 
	 * @param {Object}
	 *            deep
	 * @param {Object}
	 *            iterator
	 */
	getChildShapes : function(deep, iterator) {
		var result = [];

		this.children.each(function(uiObject) {
					if (uiObject instanceof ORYX.Core.Shape
							&& uiObject.isVisible) {
						if (iterator) {
							iterator(uiObject);
						}
						result.push(uiObject);
						if (deep) {
							result = result.concat(uiObject.getChildShapes(
									deep, iterator));
						}
					}
				});

		return result;
	},

	/**
	 * @param {Object}
	 *            shape
	 * @return {boolean} true if any of shape's childs is given shape
	 */
	hasChildShape : function(shape) {
		return this.getChildShapes().any(function(child) {
					return (child === shape) || child.hasChildShape(shape);
				});
	},

	/**
	 * 
	 * @param {Object}
	 *            deep
	 * @param {Object}
	 *            iterator
	 */
	getChildNodes : function(deep, iterator) {
		var result = [];

		this.children.each(function(uiObject) {
					if (uiObject instanceof ORYX.Core.Node
							&& uiObject.isVisible) {
						if (iterator) {
							iterator(uiObject);
						}
						result.push(uiObject);
					}
					if (uiObject instanceof ORYX.Core.Shape) {
						if (deep) {
							result = result.concat(uiObject.getChildNodes(deep,
									iterator));
						}
					}
				});

		return result;
	},

	/**
	 * 
	 * @param {Object}
	 *            deep
	 * @param {Object}
	 *            iterator
	 */
	getChildEdges : function(deep, iterator) {
		var result = [];

		this.children.each(function(uiObject) {
					if (uiObject instanceof ORYX.Core.Edge
							&& uiObject.isVisible) {
						if (iterator) {
							iterator(uiObject);
						}
						result.push(uiObject);
					}
					if (uiObject instanceof ORYX.Core.Shape) {
						if (deep) {
							result = result.concat(uiObject.getChildEdges(deep,
									iterator));
						}
					}
				});

		return result;
	},

	/**
	 * Returns a sorted array of ORYX.Core.Node objects. Ordered in z Order, the
	 * last object has the highest z Order.
	 */
	// TODO deep iterator
	getAbstractShapesAtPosition : function() {
		var x, y;
		switch (arguments.length) {
			case 1 :
				x = arguments[0].x;
				y = arguments[0].y;
				break;
			case 2 : // two or more arguments
				x = arguments[0];
				y = arguments[1];
				break;
			default :
				throw "getAbstractShapesAtPosition needs 1 or 2 arguments!"
		}

		if (this.isPointIncluded(x, y)) {

			var result = [];
			result.push(this);

			// check, if one child is at that position

			var childNodes = this.getChildNodes();
			var childEdges = this.getChildEdges();

			[childNodes, childEdges].each(function(ne) {
				var nodesAtPosition = new Hash();

				ne.each(function(node) {
					if (!node.isVisible) {
						return
					}
					var candidates = node.getAbstractShapesAtPosition(x, y);
					if (candidates.length > 0) {
						var nodesInZOrder = $A(node.node.parentNode.childNodes);
						var zOrderIndex = nodesInZOrder.indexOf(node.node);
						nodesAtPosition[zOrderIndex] = candidates;
					}
				});

				nodesAtPosition.keys().sort().each(function(key) {
							result = result.concat(nodesAtPosition[key]);
						});
			});

			return result;

		} else {
			return [];
		}
	},

	/**
	 * 
	 * @param key
	 *            {String} Must be 'prefix-id' of property
	 * @param value
	 *            {Object} Can be of type String or Number according to property
	 *            type.
	 */
	setProperty : function(key, value, force) {
		var oldValue = this.properties[key];
		if (oldValue !== value || force === true) {
			this.properties[key] = value;
			this.propertiesChanged[key] = true;
			this._changed();

			// Raise an event, to show that the property has changed
			// window.setTimeout( function(){

			if (!this._isInSetProperty) {
				this._isInSetProperty = true;

				this._delegateEvent({
							type : ORYX.CONFIG.EVENT_PROPERTY_CHANGED,
							elements : [this],
							name : key,
							value : value,
							oldValue : oldValue
						});

				delete this._isInSetProperty;
			}
			// }.bind(this), 10)
		}
	},

	/**
	 * Returns TRUE if one of the properties is flagged as dirty
	 * 
	 * @return {boolean}
	 */
	isPropertyChanged : function() {
		return this.propertiesChanged.any(function(property) {
					return property.value
				});
	},

	/**
	 * 
	 * @param {String}
	 *            Must be 'prefix-id' of property
	 * @param {Object}
	 *            Can be of type String or Number according to property type.
	 */
	setHiddenProperty : function(key, value) {
		// IF undefined, Delete
		if (value === undefined) {
			delete this.hiddenProperties[key];
			return;
		}
		var oldValue = this.hiddenProperties[key];
		if (oldValue !== value) {
			this.hiddenProperties[key] = value;
		}
	},
	/**
	 * Calculate if the point is inside the Shape
	 * 
	 * @param {Point}
	 */
	isPointIncluded : function(pointX, pointY, absoluteBounds) {
		var absBounds = absoluteBounds ? absoluteBounds : this.absoluteBounds();
		return absBounds.isIncluded(pointX, pointY);

	},

	/**
	 * Get the serialized object return Array with hash-entrees (prefix, name,
	 * value) Following values will given: Type Properties
	 */
	serialize : function() {
		var serializedObject = [];

		// Add the type
		serializedObject.push({
					name : 'type',
					prefix : 'oryx',
					value : this.getStencil().id(),
					type : 'literal'
				});

		// Add hidden properties
		this.hiddenProperties.each(function(prop) {
					serializedObject.push({
								name : prop.key.replace("oryx-", ""),
								prefix : "oryx",
								value : prop.value,
								type : 'literal'
							});
				}.bind(this));

		// Add all properties
		this.getStencil().properties().each((function(property) {

					var prefix = property.prefix(); // Get prefix
					var name = property.id(); // Get name

					// if(typeof this.properties[prefix+'-'+name] == 'boolean'
					// || this.properties[prefix+'-'+name] != "")
					serializedObject.push({
								name : name,
								prefix : prefix,
								value : this.properties[prefix + '-' + name],
								type : 'literal'
							});

				}).bind(this));

		return serializedObject;
	},

	deserialize : function(serialize) {
		// Search in Serialize
		var initializedDocker = 0;

		// Sort properties so that the hidden properties are first in the list
		serialize = serialize.sort(function(a, b) {
					a = Number(this.properties.keys().member(a.prefix + "-"
							+ a.name));
					b = Number(this.properties.keys().member(b.prefix + "-"
							+ b.name));
					return a > b ? 1 : (a < b ? -1 : 0)
				}.bind(this));

		serialize.each((function(obj) {

			var name = obj.name;
			var prefix = obj.prefix;
			var value = obj.value;

			// Complex properties can be real json objects, encode them to a
			// string
			if (Object.prototype.toString.call(value) === "Object")
				value = JSON.stringify(value);

			switch (prefix + "-" + name) {
				case 'raziel-parent' :
					// Set parent
					if (!this.parent) {
						break
					}
					;

					// Set outgoing Shape
					var parent = this.getCanvas()
							.getChildShapeByResourceId(value);
					if (parent) {
						parent.add(this);
					}

					break;
				default :
					// If list, eval as an array
					var prop = this.getStencil().property(prefix + "-" + name);
					if (prop && prop.isList() && typeof value === "string") {
						if ((value || "").strip() && !value.startsWith("[")
								&& !value.startsWith("]"))
							value = "[\"" + value.strip() + "\"]";
						value = ((value || "").strip() || "[]").evalJSON();
					}

					// Set property
					if (this.properties.keys().member(prefix + "-" + name)) {
						this.setProperty(prefix + "-" + name, value);
					} else if (!(name === "bounds" || name === "parent"
							|| name === "target" || name === "dockers"
							|| name === "docker" || name === "outgoing" || name === "incoming")) {
						this.setHiddenProperty(prefix + "-" + name, value);
					}

			}
		}).bind(this));
	},

	toString : function() {
		return "ORYX.Core.AbstractShape " + this.id
	},

	/**
	 * Converts the shape to a JSON representation.
	 * 
	 * @return {Object} A JSON object with included
	 *         ORYX.Core.AbstractShape.JSONHelper and getShape() method.
	 */
	toJSON : function() {
		var json = {
			resourceId : this.resourceId,
			properties : jQuery.extend({}, this.properties,
					this.hiddenProperties).inject({}, function(props, prop) {
				var key = prop[0];
				var value = prop[1];

				// If complex property, value should be a json object
				if (this.getStencil().property(key)
						&& this.getStencil().property(key).type() === ORYX.CONFIG.TYPE_COMPLEX
						&& Object.prototype.toString.call(value) === "String") {

					try {
						value = JSON.parse(value);
					} catch (error) {
					}
					// try {value = JSON.parse(value);} catch(error){}

					// Parse date
				} else if (value instanceof Date
						&& this.getStencil().property(key)) {
					try {
						value = value.format(this.getStencil().property(key)
								.dateFormat());
					} catch (e) {
					}
				}

				// Takes "my_property" instead of "oryx-my_property" as key
				key = key.replace(/^[\w_]+-/, "");
				props[key] = value;

				return props;
			}.bind(this)),
			stencil : {
				id : this.getStencil().idWithoutNs()
			},
			childShapes : this.getChildShapes().map(function(shape) {
						return shape.toJSON();
					})
		};

		if (this.getOutgoingShapes) {
			json.outgoing = this.getOutgoingShapes().map(function(shape) {
						return {
							resourceId : shape.resourceId
						};
					});
		}

		if (this.bounds) {
			json.bounds = {
				lowerRight : this.bounds.lowerRight(),
				upperLeft : this.bounds.upperLeft()
			};
		}

		if (this.dockers) {
			json.dockers = this.dockers.map(function(docker) {
						var d = docker.getDockedShape()
								&& docker.referencePoint
								? docker.referencePoint
								: docker.bounds.center();
						d.getDocker = function() {
							return docker;
						};
						return d;
					});
		}

		jQuery.extend(json, ORYX.Core.AbstractShape.JSONHelper);

		// do not pollute the json attributes (for serialization), so put the
		// corresponding
		// shape is encapsulated in a method
		json.getShape = function() {
			return this;
		}.bind(this);

		return json;
	}
});

/**
 * @namespace Collection of methods which can be used on a shape json object
 *            (ORYX.Core.AbstractShape#toJSON()).
 *            @example
 *            jQuery.extend(shapeAsJson, ORYX.Core.AbstractShape.JSONHelper);
 */
ORYX.Core.AbstractShape.JSONHelper = {
	/**
	 * Iterates over each child shape.
	 * 
	 * @param {Object}
	 *            iterator Iterator function getting a child shape and his
	 *            parent as arguments.
	 * @param {boolean}
	 *            [deep=false] Iterate recursively (childShapes of childShapes)
	 * @param {boolean}
	 *            [modify=false] If true, the result of the iterator function is
	 *            taken as new shape, return false to delete it. This enables
	 *            modifying the object while iterating through the child shapes.
	 *            @example // Increases the lowerRight x value of each direct child shape by one. 
	 * myShapeAsJson.eachChild(function(shape, parentShape){
	 *     shape.bounds.lowerRight.x = shape.bounds.lowerRight.x + 1;
	 *     return shape;
	 * }, false, true);
	 */
	eachChild : function(iterator, deep, modify) {
		if (!this.childShapes)
			return;

		var newChildShapes = []; // needed if modify = true

		this.childShapes.each(function(shape) {
					if (!(shape.eachChild instanceof Function)) {
						jQuery
								.extend(shape,
										ORYX.Core.AbstractShape.JSONHelper);
					}
					var res = iterator(shape, this);
					if (res)
						newChildShapes.push(res); // if false is returned, and
													// modify = true, current
													// shape is deleted.

					if (deep)
						shape.eachChild(iterator, deep, modify);
				}.bind(this));

		if (modify)
			this.childShapes = newChildShapes;
	},

	getShape : function() {
		return null;
	},
	getChildShapes : function(deep) {
		var allShapes = this.childShapes;

		if (deep) {
			this.eachChild(function(shape) {
						if (!(shape.getChildShapes instanceof Function)) {
							jQuery.extend(shape,
									ORYX.Core.AbstractShape.JSONHelper);
						}
						allShapes = allShapes
								.concat(shape.getChildShapes(deep));
					}, true);
		}

		return allShapes;
	},

	/**
	 * @return {String} Serialized JSON object
	 */
	serialize : function() {
		return JSON.stringify(this);
	}
}
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}

/**
 * @namespace Namespace for the Oryx core elements.
 * @name ORYX.Core
 */
if (!ORYX.Core) {
	ORYX.Core = {};
}

/**
 * @class Oryx canvas.
 * @extends ORYX.Core.AbstractShape
 * 
 */
ORYX.Core.Canvas = ORYX.Core.AbstractShape.extend({
	/** @lends ORYX.Core.Canvas.prototype */

	/**
	 * Defines the current zoom level
	 */
	zoomLevel : 1,

	/**
	 * Constructor
	 */
	construct : function(options, stencil, facade) {
		arguments.callee.$.construct.apply(this, arguments);

		if (!(options && options.width && options.height)) {

			ORYX.Log
					.fatal("Canvas is missing mandatory parameters options.width and options.height.");
			return;
		}
		this.facade = facade;
		// TODO: set document resource id
		this.resourceId = options.id;

		this.nodes = [];

		this.edges = [];

		// Row highlighting states
		this.colHighlightState = 0;

		this.colHighlightEnabled = false;

		// init svg document
		this.rootNode = ORYX.Editor.graft("http://www.w3.org/2000/svg",
				options.parentNode, ['svg', {
							id : this.id,
							width : options.width,
							height : options.height
						}, ['defs', {}]]);

		this.rootNode.setAttribute("xmlns:xlink",
				"http://www.w3.org/1999/xlink");
		this.rootNode.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg");

		this._htmlContainer = ORYX.Editor.graft("http://www.w3.org/1999/xhtml",
				options.parentNode, ['div', {
							id : "oryx_canvas_htmlContainer",
							style : "position:absolute; top:5px"
						}]);

		// Additional SVG-node BELOW the stencils to allow underlays (if that is
		// even a word) by plugins
		this.underlayNode = ORYX.Editor.graft("http://www.w3.org/2000/svg",
				this.rootNode, ['svg', {
							id : "underlay-container"
						}]);

		// Create 2 svg-elements in the svg-container
		this.columnHightlight1 = ORYX.Editor.graft(
				"http://www.w3.org/2000/svg", this.underlayNode, ['rect', {
							x : 0,
							width : ORYX.CONFIG.FORM_ROW_WIDTH + 35,
							height : "100%",
							style : "fill: #fff6d5",
							visibility : "hidden"
						}]);

		this.columnHightlight2 = ORYX.Editor.graft(
				"http://www.w3.org/2000/svg", this.underlayNode, ['rect', {
							x : ORYX.CONFIG.FORM_ROW_WIDTH + 35,
							width : ORYX.CONFIG.FORM_ROW_WIDTH + 25,
							height : "100%",
							style : "fill: #fff6d5",
							visibility : "hidden"
						}]);

		this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
				this.rootNode, ['g', {}, ['g', {
									"class" : "stencils"
								}, ['g', {
											"class" : "me"
										}], ['g', {
											"class" : "children"
										}], ['g', {
											"class" : "edge"
										}]], ['g', {
									"class" : "svgcontainer"
								}]]);

		/*
		 * var off = 2 * ORYX.CONFIG.GRID_DISTANCE; var size = 3; var d = "";
		 * for(var i = 0; i <= options.width; i += off) for(var j = 0; j <=
		 * options.height; j += off) d = d + "M" + (i - size) + " " + j + " l" +
		 * (2*size) + " 0 m" + (-size) + " " + (-size) + " l0 " + (2*size) + "
		 * m0" + (-size) + " ";
		 * 
		 * ORYX.Editor.graft("http://www.w3.org/2000/svg",
		 * this.node.firstChild.firstChild, ['path', {d:d , stroke:'#000000',
		 * 'stroke-width':'0.15px'},]);
		 */

		// Global definition of default font for shapes
		// Definitions in the SVG definition of a stencil will overwrite these
		// settings for
		// that stencil.
		/*
		 * if(navigator.platform.indexOf("Mac") > -1) {
		 * this.node.setAttributeNS(null, 'stroke', 'black');
		 * this.node.setAttributeNS(null, 'stroke-width', '0.5px');
		 * this.node.setAttributeNS(null, 'font-family', 'Skia');
		 * //this.node.setAttributeNS(null, 'letter-spacing', '2px');
		 * this.node.setAttributeNS(null, 'font-size',
		 * ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT); } else {
		 * this.node.setAttributeNS(null, 'stroke', 'none');
		 * this.node.setAttributeNS(null, 'font-family', 'Verdana');
		 * this.node.setAttributeNS(null, 'font-size',
		 * ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT); }
		 */

		this.node.setAttributeNS(null, 'stroke', 'none');
		this.node.setAttributeNS(null, 'font-family', 'Verdana, sans-serif');
		this.node.setAttributeNS(null, 'font-size-adjust', 'none');
		this.node.setAttributeNS(null, 'font-style', 'normal');
		this.node.setAttributeNS(null, 'font-variant', 'normal');
		this.node.setAttributeNS(null, 'font-weight', 'normal');
		this.node.setAttributeNS(null, 'line-heigth', 'normal');

		this.node.setAttributeNS(null, 'font-size',
				ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT);

		this.bounds.set(0, 0, options.width, options.height);

		this.addEventHandlers(this.rootNode.parentNode);

		// disable context menu
		this.rootNode.oncontextmenu = function() {
			return false;
		};
	},

	focus : function() {

		try {
			// Get a href
			if (!this.focusEl) {
				this.focusEl = jQuery('body')
						.append(jQuery('<a href="#" class="x-grid3-focus x-grid3-focus-canvas"/>'));
				this.focusEl.swallowEvent("click", true);
			}

			// Focus it
			this.focusEl.focus.defer(1, this.focusEl);
			this.focusEl.blur.defer(3, this.focusEl);

		} catch (e) {
		}
	},

	setHightlightState : function(state) {
		if (this.colHighlightEnabled && this.colHighlightState != state) {
			if (state == 0) {
				this.columnHightlight1.setAttribute("visibility", "hidden");
				this.columnHightlight2.setAttribute("visibility", "hidden");
			} else if (state == 1) {
				this.columnHightlight1.setAttribute("visibility", "visible");
				this.columnHightlight2.setAttribute("visibility", "hidden");
			} else if (state == 2) {
				this.columnHightlight1.setAttribute("visibility", "hidden");
				this.columnHightlight2.setAttribute("visibility", "visible");
			} else if (state == 3) {
				this.columnHightlight1.setAttribute("visibility", "visible");
				this.columnHightlight2.setAttribute("visibility", "visible");
			}
			this.colHighlightState = state;
		}
	},

	setHightlightStateBasedOnX : function(x) {
		if (x > ORYX.CONFIG.FORM_ROW_WIDTH + 30) {
			this.setHightlightState(2);
		} else {
			this.setHightlightState(1);
		}
	},

	update : function() {

		this.nodes.each(function(node) {
					this._traverseForUpdate(node);
				}.bind(this));

		// call stencil's layout callback
		// (needed for row layouting of xforms)
		// this.getStencil().layout(this);

		var layoutEvents = this.getStencil().layout();

		if (layoutEvents) {
			layoutEvents.each(function(event) {

						// setup additional attributes
						event.shape = this;
						event.forceExecution = true;
						event.target = this.rootNode;

						// do layouting

						this._delegateEvent(event);
					}.bind(this))
		}

		this.nodes.invoke("_update");

		this.edges.invoke("_update", true);

		/*
		 * this.children.each(function(child) { child._update(); });
		 */
	},

	_traverseForUpdate : function(shape) {
		var childRet = shape.isChanged;
		shape.getChildNodes(false, function(child) {
					if (this._traverseForUpdate(child)) {
						childRet = true;
					}
				}.bind(this));

		if (childRet) {
			shape.layout();
			return true;
		} else {
			return false;
		}
	},

	layout : function() {

	},

	/**
	 * 
	 * @param {Object}
	 *            deep
	 * @param {Object}
	 *            iterator
	 */
	getChildNodes : function(deep, iterator) {
		if (!deep && !iterator) {
			return this.nodes.clone();
		} else {
			var result = [];
			this.nodes.each(function(uiObject) {
						if (iterator) {
							iterator(uiObject);
						}
						result.push(uiObject);

						if (deep && uiObject instanceof ORYX.Core.Shape) {
							result = result.concat(uiObject.getChildNodes(deep,
									iterator));
						}
					});

			return result;
		}
	},

	/**
	 * buggy crap! use base class impl instead!
	 * 
	 * @param {Object}
	 *            iterator
	 */
	/*
	 * getChildEdges: function(iterator) { if(iterator) {
	 * this.edges.each(function(edge) { iterator(edge); }); }
	 * 
	 * return this.edges.clone(); },
	 */
	/**
	 * Overrides the UIObject.add method. Adds uiObject to the correct sub node.
	 * 
	 * @param {UIObject}
	 *            uiObject
	 */
	add : function(uiObject, index, silent) {
		// if uiObject is child of another UIObject, remove it.
		if (uiObject instanceof ORYX.Core.UIObject) {
			if (!(this.children.member(uiObject))) {
				// if uiObject is child of another parent, remove it from that
				// parent.
				if (uiObject.parent) {
					uiObject.parent.remove(uiObject, true);
				}

				// add uiObject to the Canvas
				// add uiObject to this Shape
				if (index != undefined)
					this.children.splice(index, 0, uiObject);
				else
					this.children.push(uiObject);

				// set parent reference
				uiObject.parent = this;

				// add uiObject.node to this.node depending on the type of
				// uiObject
				if (uiObject instanceof ORYX.Core.Shape) {
					if (uiObject instanceof ORYX.Core.Edge) {
						uiObject
								.addMarkers(this.rootNode
										.getElementsByTagNameNS(NAMESPACE_SVG,
												"defs")[0]);
						uiObject.node = this.node.childNodes[0].childNodes[2]
								.appendChild(uiObject.node);
						this.edges.push(uiObject);
					} else {
						uiObject.node = this.node.childNodes[0].childNodes[1]
								.appendChild(uiObject.node);
						this.nodes.push(uiObject);
					}
				} else { // UIObject
					uiObject.node = this.node.appendChild(uiObject.node);
				}

				uiObject.bounds.registerCallback(this._changedCallback);

				if (this.eventHandlerCallback && silent !== true)
					this.eventHandlerCallback({
								type : ORYX.CONFIG.EVENT_SHAPEADDED,
								shape : uiObject
							})
			} else {

				ORYX.Log
						.warn("add: ORYX.Core.UIObject is already a child of this object.");
			}
		} else {

			ORYX.Log.fatal("add: Parameter is not of type ORYX.Core.UIObject.");
		}
	},

	/**
	 * Overrides the UIObject.remove method. Removes uiObject.
	 * 
	 * @param {UIObject}
	 *            uiObject
	 */
	remove : function(uiObject, silent) {
		// if uiObject is a child of this object, remove it.
		if (this.children.member(uiObject)) {
			// remove uiObject from children
			var parent = uiObject.parent;

			this.children = this.children.without(uiObject);

			// delete parent reference of uiObject
			uiObject.parent = undefined;

			// delete uiObject.node from this.node
			if (uiObject instanceof ORYX.Core.Shape) {
				if (uiObject instanceof ORYX.Core.Edge) {
					uiObject.removeMarkers();
					uiObject.node = this.node.childNodes[0].childNodes[2]
							.removeChild(uiObject.node);
					this.edges = this.edges.without(uiObject);
				} else {
					uiObject.node = this.node.childNodes[0].childNodes[1]
							.removeChild(uiObject.node);
					this.nodes = this.nodes.without(uiObject);
				}
			} else { // UIObject
				uiObject.node = this.node.removeChild(uiObject.node);
			}

			if (this.eventHandlerCallback && silent !== true)
				this.eventHandlerCallback({
							type : ORYX.CONFIG.EVENT_SHAPEREMOVED,
							shape : uiObject,
							parent : parent
						});

			uiObject.bounds.unregisterCallback(this._changedCallback);
		} else {

			ORYX.Log
					.warn("remove: ORYX.Core.UIObject is not a child of this object.");
		}
	},

	/**
	 * Creates shapes out of the given collection of shape objects and adds them
	 * to the canvas.
	 * 
	 * @example
	 * canvas.addShapeObjects({
	     bounds:{ lowerRight:{ y:510, x:633 }, upperLeft:{ y:146, x:210 } },
	     resourceId:"oryx_F0715955-50F2-403D-9851-C08CFE70F8BD",
	     childShapes:[],
	     properties:{},
	     stencil:{
	       id:"Subprocess"
	     },
	     outgoing:[{resourceId: 'aShape'}],
	     target: {resourceId: 'aShape'}
	   });
	 * @param {Object}
	 *            shapeObjects
	 * @param {Function}
	 *            [eventHandler] An event handler passed to each newly created
	 *            shape (as eventHandlerCallback)
	 * @return {Array} A collection of ORYX.Core.Shape
	 * @methodOf ORYX.Core.Canvas.prototype
	 */
	addShapeObjects : function(shapeObjects, eventHandler) {
		if (!shapeObjects)
			return;

		this.initializingShapes = true;

		/*
		 * FIXME This implementation is very evil! At first, all shapes are
		 * created on canvas. In a second step, the attributes are applied.
		 * There must be a distinction between the configuration phase (where
		 * the outgoings, for example, are just named), and the creation phase
		 * (where the outgoings are evaluated). This must be reflected in code
		 * to provide a nicer API/ implementation!!!
		 */

		var addShape = function(shape, parent) {
			// Create a new Stencil
			var stencil = ORYX.Core.StencilSet.stencil(this.getStencil()
					.namespace()
					+ shape.stencil.id);

			// Create a new Shape
			var ShapeClass = (stencil.type() == "node")
					? ORYX.Core.Node
					: ORYX.Core.Edge;
			var newShape = new ShapeClass({
						'eventHandlerCallback' : eventHandler
					}, stencil, this.facade);

			// Set the resource id
			newShape.resourceId = shape.resourceId;
			newShape.node.id = "svg-" + shape.resourceId;

			// Set parent to json object to be used later
			// Due to the nested json structure, normally shape.parent is not
			// set/ must not be set.
			// In special cases, it can be easier to set this directly instead
			// of a nested structure.
			shape.parent = "#"
					+ ((shape.parent && shape.parent.resourceId) || parent.resourceId);

			// Add the shape to the canvas
			this.add(newShape);

			return {
				json : shape,
				object : newShape
			};
		}.bind(this);

		/**
		 * Builds up recursively a flatted array of shapes, including a
		 * javascript object and json representation
		 * 
		 * @param {Object}
		 *            shape Any object that has Object#childShapes
		 */
		var addChildShapesRecursively = function(shape) {
			var addedShapes = [];

			if (shape.childShapes && shape.childShapes.constructor == String) {
				shape.childShapes = JSON.parse(shape.childShapes);
			}

			shape.childShapes.each(function(childShape) {
						addedShapes.push(addShape(childShape, shape));
						addedShapes = addedShapes
								.concat(addChildShapesRecursively(childShape));
					});

			return addedShapes;
		}.bind(this);

		var shapes = addChildShapesRecursively({
					childShapes : shapeObjects,
					resourceId : this.resourceId
				});

		// prepare deserialisation parameter
		shapes.each(function(shape) {
					var properties = [];
					for (field in shape.json.properties) {
						properties.push({
									prefix : 'oryx',
									name : field,
									value : shape.json.properties[field]
								});
					}

					// Outgoings
					shape.json.outgoing.each(function(out) {
								properties.push({
											prefix : 'raziel',
											name : 'outgoing',
											value : "#" + out.resourceId
										});
							});

					// Target
					// (because of a bug, the first outgoing is taken when there
					// is no target,
					// can be removed after some time)
					if (shape.object instanceof ORYX.Core.Edge) {
						var target = shape.json.target
								|| shape.json.outgoing[0];
						if (target) {
							properties.push({
										prefix : 'raziel',
										name : 'target',
										value : "#" + target.resourceId
									});
						}
					}

					// Bounds
					if (shape.json.bounds) {
						properties.push({
									prefix : 'oryx',
									name : 'bounds',
									value : shape.json.bounds.upperLeft.x + ","
											+ shape.json.bounds.upperLeft.y
											+ ","
											+ shape.json.bounds.lowerRight.x
											+ ","
											+ shape.json.bounds.lowerRight.y
								});
					}

					// Dockers [{x:40, y:50}, {x:30, y:60}] => "40 50 30 60 #"
					if (shape.json.dockers) {
						properties.push({
									prefix : 'oryx',
									name : 'dockers',
									value : shape.json.dockers.inject("",
											function(dockersStr, docker) {
												return dockersStr + docker.x
														+ " " + docker.y + " ";
											})
											+ " #"
								});
					}

					// Parent
					properties.push({
								prefix : 'raziel',
								name : 'parent',
								value : shape.json.parent
							});

					shape.__properties = properties;
				}.bind(this));

		// Deserialize the properties from the shapes
		// This can't be done earlier because Shape#deserialize expects that all
		// referenced nodes are already there

		// first, deserialize all nodes
		shapes.each(function(shape) {
					if (shape.object instanceof ORYX.Core.Node) {
						shape.object
								.deserialize(shape.__properties, shape.json);
					}
				});

		// second, deserialize all edges
		shapes.each(function(shape) {
					if (shape.object instanceof ORYX.Core.Edge) {
						shape.object
								.deserialize(shape.__properties, shape.json);
						shape.object._oldBounds = shape.object.bounds.clone();
						shape.object._update();
					}
				});

		delete this.initializingShapes;
		return shapes.pluck("object");
	},

	/**
	 * Updates the size of the canvas, regarding to the containg shapes.
	 */
	updateSize : function() {
		// Check the size for the canvas
		var maxWidth = 0;
		var maxHeight = 0;
		var offset = 100;
		this.getChildShapes(true, function(shape) {
					var b = shape.bounds;
					maxWidth = Math.max(maxWidth, b.lowerRight().x + offset)
					maxHeight = Math.max(maxHeight, b.lowerRight().y + offset)
				});

		if (this.bounds.width() < maxWidth || this.bounds.height() < maxHeight) {
			this.setSize({
						width : Math.max(this.bounds.width(), maxWidth),
						height : Math.max(this.bounds.height(), maxHeight)
					})
		}
	},

	getRootNode : function() {
		return this.rootNode;
	},

	getUnderlayNode : function() {
		return this.underlayNode;
	},

	getSvgContainer : function() {
		return this.node.childNodes[1];
	},

	getHTMLContainer : function() {
		return this._htmlContainer;
	},

	/**
	 * Return all elements of the same highest level
	 * 
	 * @param {Object}
	 *            elements
	 */
	getShapesWithSharedParent : function(elements) {

		// If there is no elements, return []
		if (!elements || elements.length < 1) {
			return [];
		}
		// If there is one element, return this element
		if (elements.length == 1) {
			return elements;
		}

		return elements.findAll(function(value) {
					var parentShape = value.parent;
					while (parentShape) {
						if (elements.member(parentShape))
							return false;
						parentShape = parentShape.parent;
					}
					return true;
				});

	},

	setSize : function(size, dontSetBounds) {
		if (!size || !size.width || !size.height) {
			return;
		};

		if (this.rootNode.parentNode) {
			this.rootNode.parentNode.style.width = size.width + 'px';
			this.rootNode.parentNode.style.height = size.height + 'px';
		}

		this.rootNode.setAttributeNS(null, 'width', size.width);
		this.rootNode.setAttributeNS(null, 'height', size.height);

		// this._htmlContainer.style.top = "-" + (size.height + 4) + 'px';
		if (!dontSetBounds) {
			this.bounds.set({
						a : {
							x : 0,
							y : 0
						},
						b : {
							x : size.width / this.zoomLevel,
							y : size.height / this.zoomLevel
						}
					});
		}
	},

	/**
	 * Returns an SVG document of the current process.
	 * 
	 * @param {Boolean}
	 *            escapeText Use true, if you want to parse it with an
	 *            XmlParser, false, if you want to use the SVG document in
	 *            browser on client side.
	 */
	getSVGRepresentation : function(escapeText) {
		// Get the serialized svg image source
		var svgClone = this.getRootNode().cloneNode(true);

		this._removeInvisibleElements(svgClone);

		var x1, y1, x2, y2;
		this.getChildShapes(true).each(function(shape) {
					var absBounds = shape.absoluteBounds();
					var ul = absBounds.upperLeft();
					var lr = absBounds.lowerRight();
					if (x1 == undefined) {
						x1 = ul.x;
						y1 = ul.y;
						x2 = lr.x;
						y2 = lr.y;
					} else {
						x1 = Math.min(x1, ul.x);
						y1 = Math.min(y1, ul.y);
						x2 = Math.max(x2, lr.x);
						y2 = Math.max(y2, lr.y);
					}
				});

		var margin = 50;
		var width, height, tx, ty;
		if (x1 == undefined) {
			width = 0;
			height = 0;
			tx = 0;
			ty = 0;
		} else {
			width = x2;
			height = y2;
			tx = -x1 + margin / 2;
			ty = -y1 + margin / 2;
		}

		// Set the width and height
		svgClone.setAttributeNS(null, 'width', width + margin);
		svgClone.setAttributeNS(null, 'height', height + margin);

		// remove scale factor
		svgClone.childNodes[1].removeAttributeNS(null, 'transform');

		try {
			var svgCont = svgClone.childNodes[1].childNodes[1];
			svgCont.parentNode.removeChild(svgCont);
		} catch (e) {
		}

		if (escapeText) {
			$A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG,
					'tspan')).each(function(elem) {
						elem.textContent = elem.textContent.escapeHTML();
					});

			$A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG,
					'text')).each(function(elem) {
						if (elem.childNodes.length == 0)
							elem.textContent = elem.textContent.escapeHTML();
					});
		}

		// generating absolute urls for the pdf-exporter
		$A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'image'))
				.each(function(elem) {
					var href = elem.getAttributeNS(
							"http://www.w3.org/1999/xlink", "href");

					if (!href.match("^(http|https)://")) {
						href = window.location.protocol + "//"
								+ window.location.host + href;
						elem.setAttributeNS("http://www.w3.org/1999/xlink",
								"href", href);
					}
				});

		// escape all links
		$A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'a'))
				.each(function(elem) {
					elem
							.setAttributeNS("http://www.w3.org/1999/xlink",
									"xlink:href", (elem.getAttributeNS(
											"http://www.w3.org/1999/xlink",
											"href") || "").escapeHTML());
				});

		return svgClone;
	},

	/**
	 * Removes all nodes (and its children) that has the attribute visibility
	 * set to "hidden"
	 */
	_removeInvisibleElements : function(element) {
		var index = 0;
		while (index < element.childNodes.length) {
			var child = element.childNodes[index];
			if (child.getAttributeNS
					&& child.getAttributeNS(null, "visibility") === "hidden") {
				element.removeChild(child);
			} else {
				this._removeInvisibleElements(child);
				index++;
			}
		}

	},

	/**
	 * This method checks all shapes on the canvas and removes all shapes that
	 * contain invalid bounds values or dockers values(NaN)
	 */
	/*
	 * cleanUp: function(parent) { if (!parent) { parent = this; }
	 * parent.getChildShapes().each(function(shape){ var a = shape.bounds.a; var
	 * b = shape.bounds.b; if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) ||
	 * isNaN(b.y)) { parent.remove(shape); } else {
	 * shape.getDockers().any(function(docker) { a = docker.bounds.a; b =
	 * docker.bounds.b; if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) ||
	 * isNaN(b.y)) { parent.remove(shape); return true; } return false; });
	 * shape.getMagnets().any(function(magnet) { a = magnet.bounds.a; b =
	 * magnet.bounds.b; if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) ||
	 * isNaN(b.y)) { parent.remove(shape); return true; } return false; });
	 * this.cleanUp(shape); } }.bind(this)); },
	 */

	_delegateEvent : function(event) {
		if (this.eventHandlerCallback
				&& (event.target == this.rootNode || event.target == this.rootNode.parentNode)) {
			this.eventHandlerCallback(event, this);
		}
	},

	toString : function() {
		return "Canvas " + this.id
	},

	/**
	 * Calls {@link ORYX.Core.AbstractShape#toJSON} and adds some stencil set
	 * information.
	 */
	toJSON : function() {
		var json = arguments.callee.$.toJSON.apply(this, arguments);

		// if(ORYX.CONFIG.STENCILSET_HANDLER.length > 0) {
		// json.stencilset = {
		// url: this.getStencil().stencilSet().namespace()
		// };
		// } else {
		json.stencilset = {
			url : this.getStencil().stencilSet().source(),
			namespace : this.getStencil().stencilSet().namespace()
		};
		// }

		return json;
	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
var idCounter = 0;
var ID_PREFIX = "resource";

/**
 * Main initialization method. To be called when loading of the document,
 * including all scripts, is completed.
 */
function init() {

	ORYX.Log.debug("Querying editor instances");

	// Hack for WebKit to set the SVGElement-Classes
	ORYX.Editor.setMissingClasses();

	// If someone wants to create the editor instance himself
	if (window.onOryxResourcesLoaded) {
		window.onOryxResourcesLoaded();
	}
	// Else fetch the model from server and display editor
	else {
		var modelId = window.location.search.substring(4);
		var modelUrl = "./service/model/" + modelId + "/json";

		ORYX.Editor.createByUrl(modelUrl);
	}
}

/**
 * @namespace Global Oryx name space
 * @name ORYX
 */
if (!ORYX) {
	var ORYX = {};
}

/**
 * The Editor class.
 * 
 * @class ORYX.Editor
 * @extends Clazz
 * @param {Object}
 *            config An editor object, passed to
 *            {@link ORYX.Editor#loadSerialized}
 * @param {String}
 *            config.id Any ID that can be used inside the editor. If
 *            fullscreen=false, any HTML node with this id must be present to
 *            render the editor to this node.
 * @param {boolean}
 *            [config.fullscreen=true] Render editor in fullscreen mode or not.
 * @param {String}
 *            config.stencilset.url Stencil set URL.
 * @param {String}
 *            [config.stencil.id] Stencil type used for creating the canvas.
 * @param {Object}
 *            config.properties Any properties applied to the canvas.
 */
ORYX.Editor = {
	/** @lends ORYX.Editor.prototype */
	// Defines the global dom event listener
	DOMEventListeners : new Hash(),

	// Defines the selection
	selection : [],

	// Defines the current zoom level
	zoomLevel : 1.0,

	construct : function(config) {

		// initialization.
		this._eventsQueue = [];
		this.loadedPlugins = [];
		this.pluginsData = [];

		// meta data about the model for the signavio warehouse
		// directory, new, name, description, revision, model (the model data)

		this.modelMetaData = config;

		var model = config;

		this.id = model.modelId;

		if (config.model) {
			model = config.model;
		}

		if (!this.id) {
			this.id = model.id;
			if (!this.id) {
				this.id = ORYX.Editor.provideId();
			}
		}

		// Defines if the editor should be fullscreen or not
		this.fullscreen = config.fullscreen !== false;

		// Initialize the eventlistener
		this._initEventListener();

		// Load particular stencilset
		if (ORYX.CONFIG.BACKEND_SWITCH) {
			var ssUrl = (model.stencilset.namespace || model.stencilset.url)
					.replace("#", "%23");
			ORYX.Core.StencilSet.loadStencilSet(ssUrl, this.modelMetaData,
					this.id);
		} else {
			var ssUrl = model.stencilset.url;
			ORYX.Core.StencilSet.loadStencilSet(ssUrl, this.modelMetaData,
					this.id);
		}

		// CREATES the canvas
		this._createCanvas(model.stencil ? model.stencil.id : null,
				model.properties);

		// GENERATES the whole EXT.VIEWPORT
		this._generateGUI();

		// Initializing of a callback to check loading ends
		var loadPluginFinished = false;
		var loadContentFinished = false;
		var initFinished = function() {
			if (!loadPluginFinished || !loadContentFinished) {
				return
			}
			this._finishedLoading();
		}.bind(this)

		// LOAD the plugins
		window.setTimeout(function() {
					this.loadPlugins();
					loadPluginFinished = true;
					initFinished();
				}.bind(this), 100);

		// LOAD the content of the current editor instance
		window.setTimeout(function() {
					this.loadSerialized(model, true); // Request the meta data
														// as well
					this.getCanvas().update();
					loadContentFinished = true;
					initFinished();
				}.bind(this), 200);
	},

	_finishedLoading : function() {
		// Raise Loaded Event
		this.handleEvents({
					type : ORYX.CONFIG.EVENT_LOADED
				})
	},

	_initEventListener : function() {

		// Register on Events

		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYDOWN,
				this.catchKeyDownEvents.bind(this), false);
		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYUP,
				this.catchKeyUpEvents.bind(this), false);

		// Enable Key up and down Event
		this._keydownEnabled = true;
		this._keyupEnabled = true;

		this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEDOWN] = [];
		this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEUP] = [];
		this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOVER] = [];
		this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOUT] = [];
		this.DOMEventListeners[ORYX.CONFIG.EVENT_SELECTION_CHANGED] = [];
		this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEMOVE] = [];

	},

	/**
	 * Generate the whole viewport of the Editor and initialized the
	 * Ext-Framework
	 * 
	 */
	_generateGUI : function() {

		// Defines the layout height if it's NOT fullscreen
		var layoutHeight = ORYX.CONFIG.WINDOW_HEIGHT;
		var canvasParent = this.getCanvas().rootNode.parentNode;

		jQuery("#canvasSection").append(canvasParent);

		// Set the editor to the center, and refresh the size
		canvasParent.parentNode.setAttributeNS(null, 'align', 'center');
		canvasParent.setAttributeNS(null, 'align', 'left');
		this.getCanvas().setSize({
					width : ORYX.CONFIG.CANVAS_WIDTH,
					height : ORYX.CONFIG.CANVAS_HEIGHT
				});

	},

	getAvailablePlugins : function() {
		var curAvailablePlugins = ORYX.availablePlugins.clone();
		curAvailablePlugins.each(function(plugin) {
					if (this.loadedPlugins.find(function(loadedPlugin) {
								return loadedPlugin.type == this.name;
							}.bind(plugin))) {
						plugin.engaged = true;
					} else {
						plugin.engaged = false;
					}
				}.bind(this));
		return curAvailablePlugins;
	},

	loadScript : function(url, callback) {
		var script = document.createElement("script")
		script.type = "text/javascript";
		if (script.readyState) { // IE
			script.onreadystatechange = function() {
				if (script.readyState == "loaded"
						|| script.readyState == "complete") {
					script.onreadystatechange = null;
					callback();
				}
			};
		} else { // Others
			script.onload = function() {
				callback();
			};
		}
		script.src = url;
		document.getElementsByTagName("head")[0].appendChild(script);
	},
	/**
	 * activate Plugin
	 * 
	 * @param {String}
	 *            name
	 * @param {Function}
	 *            callback callback(sucess, [errorCode]) errorCodes:
	 *            NOTUSEINSTENCILSET, REQUIRESTENCILSET, NOTFOUND, YETACTIVATED
	 */
	activatePluginByName : function(name, callback, loadTry) {

		var match = this.getAvailablePlugins().find(function(value) {
					return value.name == name
				});
		if (match && (!match.engaged || (match.engaged === 'false'))) {
			var loadedStencilSetsNamespaces = this.getStencilSets().keys();
			var facade = this._getPluginFacade();
			var newPlugin;
			var me = this;
			ORYX.Log.debug("Initializing plugin '%0'", match.name);

			if (!match.requires || !match.requires.namespaces
					|| match.requires.namespaces.any(function(req) {
								return loadedStencilSetsNamespaces.indexOf(req) >= 0
							})) {
				if (!match.notUsesIn || !match.notUsesIn.namespaces
						|| !match.notUsesIn.namespaces.any(function(req) {
							return loadedStencilSetsNamespaces.indexOf(req) >= 0
						})) {

					try {

						var className = eval(match.name);
						var newPlugin = new className(facade, match);
						newPlugin.type = match.name;

						// If there is an GUI-Plugin, they get all
						// Plugins-Offer-Meta-Data
						if (newPlugin.registryChanged)
							newPlugin.registryChanged(me.pluginsData);

						// If there have an onSelection-Method it will pushed to
						// the Editor Event-Handler
						if (newPlugin.onSelectionChanged)
							me.registerOnEvent(
									ORYX.CONFIG.EVENT_SELECTION_CHANGED,
									newPlugin.onSelectionChanged
											.bind(newPlugin));
						this.loadedPlugins.push(newPlugin);
						this.loadedPlugins.each(function(loaded) {
									if (loaded.registryChanged)
										loaded
												.registryChanged(this.pluginsData);
								}.bind(me));
						callback(true);

					} catch (e) {
						ORYX.Log.warn("Plugin %0 is not available", match.name);
						if (!!loadTry) {
							callback(false, "INITFAILED");
							return;
						}
						this.loadScript("plugins/scripts/" + match.source,
								this.activatePluginByName.bind(this,
										match.name, callback, true));
					}
				} else {
					callback(false, "NOTUSEINSTENCILSET");
					ORYX.Log.info(
							"Plugin need a stencilset which is not loaded'",
							match.name);
				}

			} else {
				callback(false, "REQUIRESTENCILSET");
				ORYX.Log.info("Plugin need a stencilset which is not loaded'",
						match.name);
			}

		} else {
			callback(false, match ? "NOTFOUND" : "YETACTIVATED");
			// TODO error handling
		}
	},

	/**
	 * Laden der Plugins
	 */
	loadPlugins : function() {

		// if there should be plugins but still are none, try again.
		// TODO this should wait for every plugin respectively.
		/*
		 * if (!ORYX.Plugins && ORYX.availablePlugins.length > 0) {
		 * window.setTimeout(this.loadPlugins.bind(this), 100); return; }
		 */

		var me = this;
		var newPlugins = [];

		var loadedStencilSetsNamespaces = this.getStencilSets().keys();

		// Available Plugins will be initalize
		var facade = this._getPluginFacade();

		// If there is an Array where all plugins are described, than only take
		// those
		// (that comes from the usage of oryx with a mashup api)
		if (ORYX.MashupAPI && ORYX.MashupAPI.loadablePlugins
				&& ORYX.MashupAPI.loadablePlugins instanceof Array) {

			// Get the plugins from the available plugins (those who are in the
			// plugins.xml)
			ORYX.availablePlugins = $A(ORYX.availablePlugins).findAll(
					function(value) {
						return ORYX.MashupAPI.loadablePlugins
								.include(value.name)
					})

			// Add those plugins to the list, which are only in the
			// loadablePlugins list
			ORYX.MashupAPI.loadablePlugins.each(function(className) {
						if (!(ORYX.availablePlugins.find(function(val) {
									return val.name == className
								}))) {
							ORYX.availablePlugins.push({
										name : className
									});
						}
					})
		}

		ORYX.availablePlugins.each(function(value) {
			ORYX.Log.debug("Initializing plugin '%0'", value.name);
			if ((!value.requires || !value.requires.namespaces || value.requires.namespaces
					.any(function(req) {
								return loadedStencilSetsNamespaces.indexOf(req) >= 0
							}))
					&& (!value.notUsesIn || !value.notUsesIn.namespaces || !value.notUsesIn.namespaces
							.any(function(req) {
								return loadedStencilSetsNamespaces.indexOf(req) >= 0
							})) &&
					/* only load activated plugins or undefined */
					(value.engaged || (value.engaged === undefined))) {

				try {
					var className = eval(value.name);
					if (className) {
						var plugin = new className(facade, value);
						plugin.type = value.name;
						newPlugins.push(plugin);
						plugin.engaged = true;
					}
				} catch (e) {
					ORYX.Log.warn("Plugin %0 is not available %1", value.name,
							e);
				}

			} else {
				ORYX.Log.info("Plugin need a stencilset which is not loaded'",
						value.name);
			}

		});

		newPlugins.each(function(value) {
					// If there is an GUI-Plugin, they get all
					// Plugins-Offer-Meta-Data
					if (value.registryChanged)
						value.registryChanged(me.pluginsData);

					// If there have an onSelection-Method it will pushed to the
					// Editor Event-Handler
					if (value.onSelectionChanged)
						me.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED,
								value.onSelectionChanged.bind(value));
				});

		this.loadedPlugins = newPlugins;

		this.registerPluginsOnKeyEvents();

		this.setSelection();

	},

	/**
	 * Creates the Canvas
	 * 
	 * @param {String}
	 *            [stencilType] The stencil type used for creating the canvas.
	 *            If not given, a stencil with myBeRoot = true from current
	 *            stencil set is taken.
	 * @param {Object}
	 *            [canvasConfig] Any canvas properties (like language).
	 */
	_createCanvas : function(stencilType, canvasConfig) {
		if (stencilType) {
			// Add namespace to stencilType
			if (stencilType.search(/^http/) === -1) {
				stencilType = this.getStencilSets().values()[0].namespace()
						+ stencilType;
			}
		} else {
			// Get any root stencil type
			stencilType = this.getStencilSets().values()[0]
					.findRootStencilName();
		}

		// get the stencil associated with the type
		var canvasStencil = ORYX.Core.StencilSet.stencil(stencilType);

		if (!canvasStencil)
			ORYX.Log
					.fatal(
							"Initialisation failed, because the stencil with the type %0 is not part of one of the loaded stencil sets.",
							stencilType);

		// create all dom
		// TODO fix border, so the visible canvas has a double border and some
		// spacing to the scrollbars
		var div = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", null,
				['div']);
		// set class for custom styling
		div.addClassName("ORYX_Editor");

		// create the canvas
		this._canvas = new ORYX.Core.Canvas({
					width : ORYX.CONFIG.CANVAS_WIDTH,
					height : ORYX.CONFIG.CANVAS_HEIGHT,
					'eventHandlerCallback' : this.handleEvents.bind(this),
					id : this.id,
					parentNode : div
				}, canvasStencil, this._getPluginFacade());

		if (canvasConfig) {
			// Migrate canvasConfig to an RDF-like structure
			// FIXME this isn't nice at all because we don't want rdf any longer
			var properties = [];
			for (field in canvasConfig) {
				properties.push({
							prefix : 'oryx',
							name : field,
							value : canvasConfig[field]
						});
			}

			this._canvas.deserialize(properties);
		}

	},

	/**
	 * Returns a per-editor singleton plugin facade. To be used in plugin
	 * initialization.
	 */
	_getPluginFacade : function() {

		// if there is no pluginfacade already created:
		if (!(this._pluginFacade))

			// create it.
			this._pluginFacade = {

				activatePluginByName : this.activatePluginByName.bind(this),
				// deactivatePluginByName:
				// this.deactivatePluginByName.bind(this),
				getAvailablePlugins : this.getAvailablePlugins.bind(this),
				offer : this.offer.bind(this),
				getStencilSets : this.getStencilSets.bind(this),
				getStencilSetExtensionDefinition : function() {
					return Object.clone(this.ss_extensions_def || {})
				}.bind(this),
				getRules : this.getRules.bind(this),
				loadStencilSet : this.loadStencilSet.bind(this),
				createShape : this.createShape.bind(this),
				deleteShape : this.deleteShape.bind(this),
				getSelection : this.getSelection.bind(this),
				setSelection : this.setSelection.bind(this),
				updateSelection : this.updateSelection.bind(this),
				getCanvas : this.getCanvas.bind(this),

				importJSON : this.importJSON.bind(this),
				getJSON : this.getJSON.bind(this),
				getSerializedJSON : this.getSerializedJSON.bind(this),

				executeCommands : this.executeCommands.bind(this),
				isExecutingCommands : this.isExecutingCommands.bind(this),

				registerOnEvent : this.registerOnEvent.bind(this),
				unregisterOnEvent : this.unregisterOnEvent.bind(this),
				raiseEvent : this.handleEvents.bind(this),
				enableEvent : this.enableEvent.bind(this),
				disableEvent : this.disableEvent.bind(this),

				eventCoordinates : this.eventCoordinates.bind(this),
				eventCoordinatesXY : this.eventCoordinatesXY.bind(this),

				getModelMetaData : this.getModelMetaData.bind(this)
			};

		// return it.
		return this._pluginFacade;
	},

	isExecutingCommands : function() {
		return !!this.commandExecuting;
	},

	/**
	 * Implementes the command pattern (The real usage of the command pattern is
	 * implemented and shown in the Plugins/undo.js)
	 * 
	 * @param <Oryx.Core.Command>[]
	 *            Array of commands
	 */
	executeCommands : function(commands) {

		if (!this.commandStack) {
			this.commandStack = [];
		}
		if (!this.commandStackExecuted) {
			this.commandStackExecuted = [];
		}

		this.commandStack = [].concat(this.commandStack).concat(commands);

		// Check if already executes
		if (this.commandExecuting) {
			return;
		}

		// Start execution
		this.commandExecuting = true;

		// Iterate over all commands
		while (this.commandStack.length > 0) {
			var command = this.commandStack.shift();
			// and execute it
			command.execute();
			this.commandStackExecuted.push(command);
		}

		// Raise event for executing commands
		this.handleEvents({
					type : ORYX.CONFIG.EVENT_EXECUTE_COMMANDS,
					commands : this.commandStackExecuted
				});

		// Remove temporary vars
		delete this.commandStack;
		delete this.commandStackExecuted;
		delete this.commandExecuting;

		this.updateSelection();

	},

	/**
	 * Returns JSON of underlying canvas (calls ORYX.Canvas#toJSON()).
	 * 
	 * @return {Object} Returns JSON representation as JSON object.
	 */
	getJSON : function() {
		delete Array.prototype.toJSON;
		var canvasJSON = this.getCanvas().toJSON();
		canvasJSON.ssextensions = this.getStencilSets().values()[0]
				.extensions().keys().findAll(function(sse) {
							return !sse.endsWith('/meta#')
						});
		return canvasJSON;
	},

	/**
	 * Serializes a call to toJSON().
	 * 
	 * @return {String} Returns JSON representation as string.
	 */
	getSerializedJSON : function() {
		return JSON.stringify(this.getJSON());
	},

	/**
	 * Imports shapes in JSON as expected by {@link ORYX.Editor#loadSerialized}
	 * 
	 * @param {Object|String}
	 *            jsonObject The (serialized) json object to be imported
	 * @param {boolean }
	 *            [noSelectionAfterImport=false] Set to true if no shapes should
	 *            be selected after import
	 * @throws {SyntaxError}
	 *             If the serialized json object contains syntax errors
	 */
	importJSON : function(jsonObject, noSelectionAfterImport) {

		try {
			jsonObject = this.renewResourceIds(jsonObject);
		} catch (error) {
			throw error;
		}
		// check, if the imported json model can be loaded in this editor
		// (stencil set has to fit)
		if (jsonObject.stencilset.namespace
				&& jsonObject.stencilset.namespace !== this.getCanvas()
						.getStencil().stencilSet().namespace()) {
			alert(String.format(ORYX.I18N.JSONImport.wrongSS,
					jsonObject.stencilset.namespace, this.getCanvas()
							.getStencil().stencilSet().namespace()));
			return null;
		} else {
			var commandClass = ORYX.Core.Command.extend({
				construct : function(jsonObject, loadSerializedCB,
						noSelectionAfterImport, facade) {
					this.jsonObject = jsonObject;
					this.noSelection = noSelectionAfterImport;
					this.facade = facade;
					this.shapes;
					this.connections = [];
					this.parents = new Hash();
					this.selection = this.facade.getSelection();
					this.loadSerialized = loadSerializedCB;
				},
				execute : function() {

					if (!this.shapes) {
						// Import the shapes out of the serialization
						this.shapes = this.loadSerialized(this.jsonObject);

						// store all connections
						this.shapes.each(function(shape) {

							if (shape.getDockers) {
								var dockers = shape.getDockers();
								if (dockers) {
									if (dockers.length > 0) {
										this.connections
												.push([
														dockers.first(),
														dockers
																.first()
																.getDockedShape(),
														dockers.first().referencePoint]);
									}
									if (dockers.length > 1) {
										this.connections
												.push([
														dockers.last(),
														dockers
																.last()
																.getDockedShape(),
														dockers.last().referencePoint]);
									}
								}
							}

							// store parents
							this.parents[shape.id] = shape.parent;
						}.bind(this));
					} else {
						this.shapes.each(function(shape) {
									this.parents[shape.id].add(shape);
								}.bind(this));

						this.connections.each(function(con) {
									con[0].setDockedShape(con[1]);
									con[0].setReferencePoint(con[2]);
									con[0].update();
								});
					}

					// this.parents.values().uniq().invoke("update");
					this.facade.getCanvas().update();

					if (!this.noSelection)
						this.facade.setSelection(this.shapes);
					else
						this.facade.updateSelection();

					// call updateSize again, because during loadSerialized the
					// edges' bounds
					// are not yet initialized properly
					this.facade.getCanvas().updateSize();

				},
				rollback : function() {
					var selection = this.facade.getSelection();

					this.shapes.each(function(shape) {
								selection = selection.without(shape);
								this.facade.deleteShape(shape);
							}.bind(this));

					/*
					 * this.parents.values().uniq().each(function(parent) {
					 * if(!this.shapes.member(parent)) parent.update();
					 * }.bind(this));
					 */

					this.facade.getCanvas().update();

					this.facade.setSelection(selection);
				}
			})

			var command = new commandClass(jsonObject, this.loadSerialized
							.bind(this), noSelectionAfterImport, this
							._getPluginFacade());

			this.executeCommands([command]);

			return command.shapes.clone();
		}
	},

	/**
	 * This method renew all resource Ids and according references. Warning: The
	 * implementation performs a substitution on the serialized object for
	 * easier implementation. This results in a low performance which is
	 * acceptable if this is only used when importing models.
	 * 
	 * @param {Object|String}
	 *            jsonObject
	 * @throws {SyntaxError}
	 *             If the serialized json object contains syntax errors.
	 * @return {Object} The jsonObject with renewed ids.
	 * @private
	 */
	renewResourceIds : function(jsonObject) {
		// For renewing resource ids, a serialized and object version is needed
		if (Object.prototype.toString.call(jsonObject) === "String") {
			try {
				var serJsonObject = jsonObject;
				jsonObject = JSON.parse(jsonObject);
			} catch (error) {
				throw new SyntaxError(error.message);
			}
		} else {
			var serJsonObject = JSON.stringify(jsonObject);
		}

		// collect all resourceIds recursively
		var collectResourceIds = function(shapes) {
			if (!shapes)
				return [];

			return shapes.map(function(shape) {
				return collectResourceIds(shape.childShapes)
						.concat(shape.resourceId);
			}).flatten();
		}
		var resourceIds = collectResourceIds(jsonObject.childShapes);

		// Replace each resource id by a new one
		resourceIds.each(function(oldResourceId) {
					var newResourceId = ORYX.Editor.provideId();
					serJsonObject = serJsonObject.replace(new RegExp(
									oldResourceId, 'g'), newResourceId);
				});

		return JSON.parse(serJsonObject);
	},

	/**
	 * Loads serialized model to the oryx.
	 * 
	 * @example
	 * editor.loadSerialized({
	 *    resourceId: "mymodel1",
	 *    childShapes: [
	 *       {
	 *          stencil:{ id:"Subprocess" },
	 *          outgoing:[{resourceId: 'aShape'}],
	 *          target: {resourceId: 'aShape'},
	 *          bounds:{ lowerRight:{ y:510, x:633 }, upperLeft:{ y:146, x:210 } },
	 *          resourceId: "myshape1",
	 *          childShapes:[],
	 *          properties:{},
	 *       }
	 *    ],
	 *    properties:{
	 *       language: "English"
	 *    },
	 *    stencilset:{
	 *       url:"http://localhost:8080/oryx/stencilsets/bpmn1.1/bpmn1.1.json"
	 *    },
	 *    stencil:{
	 *       id:"BPMNDiagram"
	 *    }
	 * });
	 * @param {Object}
	 *            model Description of the model to load.
	 * @param {Array}
	 *            [model.ssextensions] List of stenctil set extensions.
	 * @param {String}
	 *            model.stencilset.url
	 * @param {String}
	 *            model.stencil.id
	 * @param {Array}
	 *            model.childShapes
	 * @param {Array}
	 *            [model.properties]
	 * @param {String}
	 *            model.resourceId
	 * @return {ORYX.Core.Shape[]} List of created shapes
	 * @methodOf ORYX.Editor.prototype
	 */
	loadSerialized : function(model, requestMeta) {
		var canvas = this.getCanvas();

		// Bugfix (cf.
		// http://code.google.com/p/oryx-editor/issues/detail?id=240)
		// Deserialize the canvas' stencil set extensions properties first!
		this.loadSSExtensions(model.ssextensions);

		// Load Meta Data Extension if available
		// #Signavio
		if (requestMeta === true) {
			var metaDataExtension = this.getExtensionForMetaData();
			if (metaDataExtension) {
				this.loadSSExtension(metaDataExtension);
			}
		}

		var shapes = this.getCanvas().addShapeObjects(model.childShapes,
				this.handleEvents.bind(this));

		if (model.properties) {
			for (key in model.properties) {
				var value = model.properties[key];
				var prop = this.getCanvas().getStencil()
						.property("oryx-" + key);
				if (!(typeof value === "string") && (!prop || !prop.isList())) {
					value = JSON.stringify(value);
				}
				this.getCanvas().setProperty("oryx-" + key, value);
			}
		}

		this.getCanvas().updateSize();

		// Force to update the selection
		this.selection = [null];
		this.setSelection([]);

		return shapes;
	},

	/**
	 * Return the namespace of the extension which provided all the self defined
	 * meta data
	 * 
	 * @return {String} Returns null if no extension is defined, otherwise the
	 *         namespace
	 * 
	 */
	getExtensionForMetaData : function() {
		if (!this.ss_extensions_def
				|| !(this.ss_extensions_def.extensions instanceof Array)) {
			return null;
		}

		var stencilsets = this.getStencilSets();
		var extension = this.ss_extensions_def.extensions.find(function(ex) {
					return !!stencilsets[ex["extends"]]
							&& ex.namespace.endsWith("/meta#");
				});

		return extension ? extension.namespace || null : null;
	},

	/**
	 * Calls ORYX.Editor.prototype.ss_extension_namespace for each element
	 * 
	 * @param {Array}
	 *            ss_extension_namespaces An array of stencil set extension
	 *            namespaces.
	 */
	loadSSExtensions : function(ss_extension_namespaces) {
		if (!ss_extension_namespaces)
			return;

		ss_extension_namespaces.each(function(ss_extension_namespace) {
					this.loadSSExtension(ss_extension_namespace);
				}.bind(this));
	},

	/**
	 * Loads a stencil set extension. The stencil set extensions definiton file
	 * must already be loaded when the editor is initialized.
	 */
	loadSSExtension : function(ss_extension_namespace) {

		if (this.ss_extensions_def) {
			var extension = this.ss_extensions_def.extensions.find(
					function(ex) {
						return (ex.namespace == ss_extension_namespace);
					});

			if (!extension) {
				return;
			}

			var stencilset = this.getStencilSets()[extension["extends"]];

			if (!stencilset) {
				return;
			}

			// Check if absolute or relative url
			if ((extension["definition"] || "").startsWith("/")) {
				stencilset.addExtension(extension["definition"])
			} else {
				stencilset.addExtension(ORYX.CONFIG.SS_EXTENSIONS_FOLDER
						+ extension["definition"])
			}

			// stencilset.addExtension("/oryx/build/stencilsets/extensions/" +
			// extension["definition"])
			this.getRules().initializeRules(stencilset);

			this._getPluginFacade().raiseEvent({
						type : ORYX.CONFIG.EVENT_STENCIL_SET_LOADED
					});
		}

	},

	disableEvent : function(eventType) {
		if (eventType == ORYX.CONFIG.EVENT_KEYDOWN) {
			this._keydownEnabled = false;
		}
		if (eventType == ORYX.CONFIG.EVENT_KEYUP) {
			this._keyupEnabled = false;
		}
		if (this.DOMEventListeners.keys().member(eventType)) {
			var value = this.DOMEventListeners.remove(eventType);
			this.DOMEventListeners['disable_' + eventType] = value;
		}
	},

	enableEvent : function(eventType) {
		if (eventType == ORYX.CONFIG.EVENT_KEYDOWN) {
			this._keydownEnabled = true;
		}

		if (eventType == ORYX.CONFIG.EVENT_KEYUP) {
			this._keyupEnabled = true;
		}

		if (this.DOMEventListeners.keys().member("disable_" + eventType)) {
			var value = this.DOMEventListeners.remove("disable_" + eventType);
			this.DOMEventListeners[eventType] = value;
		}
	},

	/**
	 * Methods for the PluginFacade
	 */
	registerOnEvent : function(eventType, callback) {
		if (!(this.DOMEventListeners.keys().member(eventType))) {
			this.DOMEventListeners[eventType] = [];
		}

		this.DOMEventListeners[eventType].push(callback);
	},

	unregisterOnEvent : function(eventType, callback) {
		if (this.DOMEventListeners.keys().member(eventType)) {
			this.DOMEventListeners[eventType] = this.DOMEventListeners[eventType]
					.without(callback);
		} else {
			// Event is not supported
			// TODO: Error Handling
		}
	},

	getSelection : function() {
		return this.selection || [];
	},

	getStencilSets : function() {
		return ORYX.Core.StencilSet.stencilSets(this.id);
	},

	getRules : function() {
		return ORYX.Core.StencilSet.rules(this.id);
	},

	loadStencilSet : function(source) {
		try {
			ORYX.Core.StencilSet.loadStencilSet(source, this.modelMetaData,
					this.id);
			this.handleEvents({
						type : ORYX.CONFIG.EVENT_STENCIL_SET_LOADED
					});
		} catch (e) {
			ORYX.Log.warn("Requesting stencil set file failed. (" + e + ")");
		}
	},

	offer : function(pluginData) {
		if (!this.pluginsData.member(pluginData)) {
			this.pluginsData.push(pluginData);
		}
	},

	/**
	 * It creates an new event or adds the callback, if already existing, for
	 * the key combination that the plugin passes in keyCodes attribute of the
	 * offer method.
	 * 
	 * The new key down event fits the schema:
	 * key.event[.metactrl][.alt][.shift].'thekeyCode'
	 */
	registerPluginsOnKeyEvents : function() {
		this.pluginsData.each(function(pluginData) {

			if (pluginData.keyCodes) {

				pluginData.keyCodes.each(function(keyComb) {
					var eventName = "key.event";

					/* Include key action */
					eventName += '.' + keyComb.keyAction;

					if (keyComb.metaKeys) {
						/* Register on ctrl or apple meta key as meta key */
						if (keyComb.metaKeys
								.indexOf(ORYX.CONFIG.META_KEY_META_CTRL) > -1) {
							eventName += "." + ORYX.CONFIG.META_KEY_META_CTRL;
						}

						/* Register on alt key as meta key */
						if (keyComb.metaKeys.indexOf(ORYX.CONFIG.META_KEY_ALT) > -1) {
							eventName += '.' + ORYX.CONFIG.META_KEY_ALT;
						}

						/* Register on shift key as meta key */
						if (keyComb.metaKeys
								.indexOf(ORYX.CONFIG.META_KEY_SHIFT) > -1) {
							eventName += '.' + ORYX.CONFIG.META_KEY_SHIFT;
						}
					}

					/* Register on the actual key */
					if (keyComb.keyCode) {
						eventName += '.' + keyComb.keyCode;
					}

					/* Register the event */
					ORYX.Log.debug("Register Plugin on Key Event: %0",
							eventName);
					if (pluginData.toggle === true && pluginData.buttonInstance) {
						this.registerOnEvent(eventName, function() {
							pluginData.buttonInstance
									.toggle(!pluginData.buttonInstance.pressed); // Toggle
							pluginData.functionality.call(pluginData,
									pluginData.buttonInstance,
									pluginData.buttonInstance.pressed); // Call
																		// function
						});
					} else {
						this.registerOnEvent(eventName,
								pluginData.functionality)
					}

				}.bind(this));
			}
		}.bind(this));
	},

	isEqual : function(a, b) {
		return a === b || (a.length === b.length && a.all(function(r) {
					return b.include(r)
				}))
	},

	isDirty : function(a) {
		return a.any(function(shape) {
					return shape.isPropertyChanged()
				})
	},

	setSelection : function(elements, subSelectionElement, force) {

		if (!elements) {
			elements = [];
		}
		if (!(elements instanceof Array)) {
			elements = [elements];
		}

		elements = elements.findAll(function(n) {
					return n && n instanceof ORYX.Core.Shape
				});

		if (elements[0] instanceof ORYX.Core.Canvas) {
			elements = [];
		}

		if (!force && this.isEqual(this.selection, elements)
				&& !this.isDirty(elements)) {
			return;
		}

		this.selection = elements;
		this._subSelection = subSelectionElement;

		this.handleEvents({
					type : ORYX.CONFIG.EVENT_SELECTION_CHANGED,
					elements : elements,
					subSelection : subSelectionElement,
					force : !!force
				})
	},

	updateSelection : function() {
		this.setSelection(this.selection, this._subSelection, true);
		/*
		 * var s = this.selection; this.setSelection(); this.setSelection(s);
		 */
	},

	getCanvas : function() {
		return this._canvas;
	},

	/**
	 * option = { type: string, position: {x:int, y:int}, connectingType:
	 * uiObj-Class connectedShape: uiObj draggin: bool namespace: url parent:
	 * ORYX.Core.AbstractShape template: a template shape that the newly created
	 * inherits properties from. }
	 */
	createShape : function(option) {

		if (option && option.serialize && option.serialize instanceof Array) {

			var type = option.serialize.find(function(obj) {
						return (obj.prefix + "-" + obj.name) == "oryx-type"
					});
			var stencil = ORYX.Core.StencilSet.stencil(type.value);

			if (stencil.type() == 'node') {
				var newShapeObject = new ORYX.Core.Node({
							'eventHandlerCallback' : this.handleEvents
									.bind(this)
						}, stencil, this._getPluginFacade());
			} else {
				var newShapeObject = new ORYX.Core.Edge({
							'eventHandlerCallback' : this.handleEvents
									.bind(this)
						}, stencil, this._getPluginFacade());
			}

			this.getCanvas().add(newShapeObject);
			newShapeObject.deserialize(option.serialize);

			return newShapeObject;
		}

		// If there is no argument, throw an exception
		if (!option || !option.type || !option.namespace) {
			throw "To create a new shape you have to give an argument with type and namespace";
		}

		var canvas = this.getCanvas();
		var newShapeObject;

		// Get the shape type
		var shapetype = option.type;

		// Get the stencil set
		var sset = ORYX.Core.StencilSet.stencilSet(option.namespace);
		// Create an New Shape, dependents on an Edge or a Node
		if (sset.stencil(shapetype).type() == "node") {
			newShapeObject = new ORYX.Core.Node({
						'eventHandlerCallback' : this.handleEvents.bind(this)
					}, sset.stencil(shapetype), this._getPluginFacade())
		} else {
			newShapeObject = new ORYX.Core.Edge({
						'eventHandlerCallback' : this.handleEvents.bind(this)
					}, sset.stencil(shapetype), this._getPluginFacade())
		}

		// when there is a template, inherit the properties.
		if (option.template) {

			newShapeObject._jsonStencil.properties = option.template._jsonStencil.properties;
			newShapeObject.postProcessProperties();
		}

		// Add to the canvas
		if (option.parent && newShapeObject instanceof ORYX.Core.Node) {
			option.parent.add(newShapeObject);
		} else {
			canvas.add(newShapeObject);
		}

		// Set the position
		var point = option.position ? option.position : {
			x : 100,
			y : 200
		};

		var con;
		// If there is create a shape and in the argument there is given an
		// ConnectingType and is instance of an edge
		if (option.connectingType && option.connectedShape
				&& !(newShapeObject instanceof ORYX.Core.Edge)) {

			// there will be create a new Edge
			con = new ORYX.Core.Edge({
						'eventHandlerCallback' : this.handleEvents.bind(this)
					}, sset.stencil(option.connectingType));

			// And both endings dockers will be referenced to the both shapes
			con.dockers.first().setDockedShape(option.connectedShape);

			var magnet = option.connectedShape.getDefaultMagnet()
			var cPoint = magnet
					? magnet.bounds.center()
					: option.connectedShape.bounds.midPoint();
			con.dockers.first().setReferencePoint(cPoint);
			con.dockers.last().setDockedShape(newShapeObject);
			con.dockers.last().setReferencePoint(newShapeObject
					.getDefaultMagnet().bounds.center());

			// The Edge will be added to the canvas and be updated
			canvas.add(con);
			// con.update();

		}

		// Move the new Shape to the position
		if (newShapeObject instanceof ORYX.Core.Edge && option.connectedShape) {

			newShapeObject.dockers.first()
					.setDockedShape(option.connectedShape);

			if (option.connectedShape instanceof ORYX.Core.Node) {
				newShapeObject.dockers.first()
						.setReferencePoint(option.connectedShape
								.getDefaultMagnet().bounds.center());
				newShapeObject.dockers.last().bounds.centerMoveTo(point);
			} else {
				newShapeObject.dockers.first()
						.setReferencePoint(option.connectedShape.bounds
								.midPoint());
			}

			var start = newShapeObject.dockers.first();
			var end = newShapeObject.dockers.last();

			if (start.getDockedShape() && end.getDockedShape()) {
				var startPoint = start.getAbsoluteReferencePoint();
				var endPoint = end.getAbsoluteReferencePoint();

				var docker = newShapeObject.createDocker();
				docker.bounds.centerMoveTo({
							x : startPoint.x + (endPont.x - startPoint.x) / 2,
							y : startPoint.y + (endPont.y - startPoint.y) / 2
						});
			}

		} else {

			var b = newShapeObject.bounds
			if (newShapeObject instanceof ORYX.Core.Node
					&& newShapeObject.dockers.length == 1) {
				b = newShapeObject.dockers.first().bounds
			}

			b.centerMoveTo(point);

			var upL = b.upperLeft();
			b.moveBy(-Math.min(upL.x, 0), -Math.min(upL.y, 0))

			var lwR = b.lowerRight();
			b.moveBy(-Math.max(lwR.x - canvas.bounds.width(), 0), -Math.max(
							lwR.y - canvas.bounds.height(), 0))

		}

		// Update the shape
		if (newShapeObject instanceof ORYX.Core.Edge) {
			newShapeObject._update(false);
		}

		// And refresh the selection
		if (!(newShapeObject instanceof ORYX.Core.Edge)
				&& !(option.dontUpdateSelection)) {
			this.setSelection([newShapeObject]);
		}

		if (con && con.alignDockers) {
			// con.alignDockers();
		}
		if (newShapeObject.alignDockers) {
			newShapeObject.alignDockers();
		}

		return newShapeObject;
	},

	deleteShape : function(shape) {

		if (!shape || !shape.parent) {
			return
		}

		// remove shape from parent
		// this also removes it from DOM
		shape.parent.remove(shape);

		// delete references to outgoing edges
		shape.getOutgoingShapes().each(function(os) {
					var docker = os.getDockers().first();
					if (docker && docker.getDockedShape() == shape) {
						docker.setDockedShape(undefined);
					}
				});

		// delete references to incoming edges
		shape.getIncomingShapes().each(function(is) {
					var docker = is.getDockers().last();
					if (docker && docker.getDockedShape() == shape) {
						docker.setDockedShape(undefined);
					}
				});

		// delete references of the shape's dockers
		shape.getDockers().each(function(docker) {
					docker.setDockedShape(undefined);
				});
	},

	/**
	 * Returns an object with meta data about the model. Like name, description,
	 * ...
	 * 
	 * Empty object with the current backend.
	 * 
	 * @return {Object} Meta data about the model
	 */
	getModelMetaData : function() {
		return this.modelMetaData;
	},

	/* Event-Handler Methods */

	/**
	 * Helper method to execute an event immediately. The event is not scheduled
	 * in the _eventsQueue. Needed to handle Layout-Callbacks.
	 */
	_executeEventImmediately : function(eventObj) {
		if (this.DOMEventListeners.keys().member(eventObj.event.type)) {
			this.DOMEventListeners[eventObj.event.type].each((function(value) {
						value(eventObj.event, eventObj.arg);
					}).bind(this));
		}
	},

	_executeEvents : function() {
		this._queueRunning = true;
		while (this._eventsQueue.length > 0) {
			var val = this._eventsQueue.shift();
			this._executeEventImmediately(val);
		}
		this._queueRunning = false;
	},

	/**
	 * Leitet die Events an die Editor-Spezifischen Event-Methoden weiter
	 * 
	 * @param {Object}
	 *            event Event , welches gefeuert wurde
	 * @param {Object}
	 *            uiObj Target-UiObj
	 */
	handleEvents : function(event, uiObj) {

		ORYX.Log.trace("Dispatching event type %0 on %1", event.type, uiObj);

		switch (event.type) {
			case ORYX.CONFIG.EVENT_MOUSEDOWN :
				this._handleMouseDown(event, uiObj);
				break;
			case ORYX.CONFIG.EVENT_MOUSEMOVE :
				this._handleMouseMove(event, uiObj);
				break;
			case ORYX.CONFIG.EVENT_MOUSEUP :
				this._handleMouseUp(event, uiObj);
				break;
			case ORYX.CONFIG.EVENT_MOUSEOVER :
				this._handleMouseHover(event, uiObj);
				break;
			case ORYX.CONFIG.EVENT_MOUSEOUT :
				this._handleMouseOut(event, uiObj);
				break;
		}
		/* Force execution if necessary. Used while handle Layout-Callbacks. */
		if (event.forceExecution) {
			this._executeEventImmediately({
						event : event,
						arg : uiObj
					});
		} else {
			this._eventsQueue.push({
						event : event,
						arg : uiObj
					});
		}

		if (!this._queueRunning) {
			this._executeEvents();
		}

		// TODO: Make this return whether no listener returned false.
		// So that, when one considers bubbling undesireable, it won't happen.
		return false;
	},

	isValidEvent : function(e) {
		try {
			var isInput = ["INPUT", "TEXTAREA"].include(e.target.tagName
					.toUpperCase());
			var gridHasFocus = e.target.className.include("x-grid3-focus")
					&& !e.target.className.include("x-grid3-focus-canvas");
			return !isInput && !gridHasFocus;
		} catch (e) {
			return false;
		}
	},

	catchKeyUpEvents : function(event) {
		if (!this._keyupEnabled) {
			return;
		}
		/* assure we have the current event. */
		if (!event)
			event = window.event;

		// Checks if the event comes from some input field
		if (!this.isValidEvent(event)) {
			return;
		}

		/* Create key up event type */
		var keyUpEvent = this.createKeyCombEvent(event,
				ORYX.CONFIG.KEY_ACTION_UP);

		ORYX.Log.debug("Key Event to handle: %0", keyUpEvent);

		/* forward to dispatching. */
		this.handleEvents({
					type : keyUpEvent,
					event : event
				});
	},

	/**
	 * Catches all key down events and forward the appropriated event to
	 * dispatching concerning to the pressed keys.
	 * 
	 * @param {Event}
	 *            The key down event to handle
	 */
	catchKeyDownEvents : function(event) {
		if (!this._keydownEnabled) {
			return;
		}
		/* Assure we have the current event. */
		if (!event)
			event = window.event;

		/* Fixed in FF3 */
		// This is a mac-specific fix. The mozilla event object has no knowledge
		// of meta key modifier on osx, however, it is needed for certain
		// shortcuts. This fix adds the metaKey field to the event object, so
		// that all listeners that registered per Oryx plugin facade profit from
		// this. The original bug is filed in
		// https://bugzilla.mozilla.org/show_bug.cgi?id=418334
		// if (this.__currentKey == ORYX.CONFIG.KEY_CODE_META) {
		// event.appleMetaKey = true;
		// }
		// this.__currentKey = pressedKey;
		// Checks if the event comes from some input field
		if (!this.isValidEvent(event)) {
			return;
		}

		/* Create key up event type */
		var keyDownEvent = this.createKeyCombEvent(event,
				ORYX.CONFIG.KEY_ACTION_DOWN);

		ORYX.Log.debug("Key Event to handle: %0", keyDownEvent);

		/* Forward to dispatching. */
		this.handleEvents({
					type : keyDownEvent,
					event : event
				});
	},

	/**
	 * Creates the event type name concerning to the pressed keys.
	 * 
	 * @param {Event}
	 *            keyDownEvent The source keyDownEvent to build up the event
	 *            name
	 */
	createKeyCombEvent : function(keyEvent, keyAction) {

		/* Get the currently pressed key code. */
		var pressedKey = keyEvent.which || keyEvent.keyCode;
		// this.__currentKey = pressedKey;

		/* Event name */
		var eventName = "key.event";

		/* Key action */
		if (keyAction) {
			eventName += "." + keyAction;
		}

		/* Ctrl or apple meta key is pressed */
		if (keyEvent.ctrlKey || keyEvent.metaKey) {
			eventName += "." + ORYX.CONFIG.META_KEY_META_CTRL;
		}

		/* Alt key is pressed */
		if (keyEvent.altKey) {
			eventName += "." + ORYX.CONFIG.META_KEY_ALT;
		}

		/* Alt key is pressed */
		if (keyEvent.shiftKey) {
			eventName += "." + ORYX.CONFIG.META_KEY_SHIFT;
		}

		/* Return the composed event name */
		return eventName + "." + pressedKey;
	},

	_handleMouseDown : function(event, uiObj) {

		// get canvas.
		var canvas = this.getCanvas();
		// Try to get the focus
		canvas.focus()

		// find the shape that is responsible for this element's id.
		var element = event.currentTarget;
		var elementController = uiObj;

		// gather information on selection.
		var currentIsSelectable = (elementController !== null)
				&& (elementController !== undefined)
				&& (elementController.isSelectable);
		var currentIsMovable = (elementController !== null)
				&& (elementController !== undefined)
				&& (elementController.isMovable);
		var modifierKeyPressed = event.shiftKey || event.ctrlKey;
		var noObjectsSelected = this.selection.length === 0;
		var currentIsSelected = this.selection.member(elementController);

		// Rule #1: When there is nothing selected, select the clicked object.
		if (currentIsSelectable && noObjectsSelected) {

			this.setSelection([elementController]);

			ORYX.Log.trace("Rule #1 applied for mouse down on %0", element.id);

			// Rule #3: When at least one element is selected, and there is no
			// control key pressed, and the clicked object is not selected,
			// select
			// the clicked object.
		} else if (currentIsSelectable && !noObjectsSelected
				&& !modifierKeyPressed && !currentIsSelected) {

			this.setSelection([elementController]);

			// var objectType = elementController.readAttributes();
			// alert(objectType[0] + ": " + objectType[1]);

			ORYX.Log.trace("Rule #3 applied for mouse down on %0", element.id);

			// Rule #4: When the control key is pressed, and the current object
			// is
			// not selected, add it to the selection.
		} else if (currentIsSelectable && modifierKeyPressed
				&& !currentIsSelected) {

			var newSelection = this.selection.clone();
			newSelection.push(elementController)
			this.setSelection(newSelection)

			ORYX.Log.trace("Rule #4 applied for mouse down on %0", element.id);

			// Rule #6
		} else if (currentIsSelectable && currentIsSelected
				&& modifierKeyPressed) {

			var newSelection = this.selection.clone();
			this.setSelection(newSelection.without(elementController))

			ORYX.Log.trace("Rule #6 applied for mouse down on %0",
					elementController.id);

			// Rule #5: When there is at least one object selected and no
			// control
			// key pressed, we're dragging.
			/*
			 * } else if(currentIsSelectable && !noObjectsSelected &&
			 * !modifierKeyPressed) {
			 * 
			 * if(this.log.isTraceEnabled()) this.log.trace("Rule #5 applied for
			 * mouse down on "+element.id);
			 */
			// Rule #2: When clicked on something that is neither
			// selectable nor movable, clear the selection, and return.
		} else if (!currentIsSelectable && !currentIsMovable) {

			this.setSelection([]);

			ORYX.Log.trace("Rule #2 applied for mouse down on %0", element.id);

			return;

			// Rule #7: When the current object is not selectable but movable,
			// it is probably a control. Leave the selection unchanged but set
			// the movedObject to the current one and enable Drag. Dockers will
			// be processed in the dragDocker plugin.
		} else if (!currentIsSelectable && currentIsMovable
				&& !(elementController instanceof ORYX.Core.Controls.Docker)) {

			// TODO: If there is any moveable elements, do this in a plugin
			// ORYX.Core.UIEnableDrag(event, elementController);

			ORYX.Log.trace("Rule #7 applied for mouse down on %0", element.id);

			// Rule #8: When the element is selectable and is currently selected
			// and no
			// modifier key is pressed
		} else if (currentIsSelectable && currentIsSelected
				&& !modifierKeyPressed) {

			this._subSelection = this._subSelection != elementController
					? elementController
					: undefined;

			this.setSelection(this.selection, this._subSelection);

			ORYX.Log.trace("Rule #8 applied for mouse down on %0", element.id);
		}

		// prevent event from bubbling, return.
		// Event.stop(event);
		return;
	},

	_handleMouseMove : function(event, uiObj) {
		return;
	},

	_handleMouseUp : function(event, uiObj) {
		// get canvas.
		var canvas = this.getCanvas();

		// find the shape that is responsible for this elemement's id.
		var elementController = uiObj;

		// get event position
		var evPos = this.eventCoordinates(event);

		// Event.stop(event);
	},

	_handleMouseHover : function(event, uiObj) {
		return;
	},

	_handleMouseOut : function(event, uiObj) {
		return;
	},

	/**
	 * Calculates the event coordinates to SVG document coordinates.
	 * 
	 * @param {Event}
	 *            event
	 * @return {SVGPoint} The event coordinates in the SVG document
	 */
	eventCoordinates : function(event) {

		var canvas = this.getCanvas();

		var svgPoint = canvas.node.ownerSVGElement.createSVGPoint();
		svgPoint.x = event.clientX;
		svgPoint.y = event.clientY;

		var additionalIEZoom = 1;
		if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
			var ua = navigator.userAgent;
			if (ua.indexOf('MSIE') >= 0) {
				// IE 10 and below
				var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI)
						* 100);
				if (zoom !== 100) {
					additionalIEZoom = zoom / 100
				}
			}
		}

		if (additionalIEZoom !== 1) {
			svgPoint.x = svgPoint.x * additionalIEZoom;
			svgPoint.y = svgPoint.y * additionalIEZoom;
		}

		var matrix = canvas.node.getScreenCTM();
		return svgPoint.matrixTransform(matrix.inverse());
	},

	eventCoordinatesXY : function(x, y) {

		var canvas = this.getCanvas();

		var svgPoint = canvas.node.ownerSVGElement.createSVGPoint();
		svgPoint.x = x;
		svgPoint.y = y;

		var additionalIEZoom = 1;
		if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
			var ua = navigator.userAgent;
			if (ua.indexOf('MSIE') >= 0) {
				// IE 10 and below
				var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI)
						* 100);
				if (zoom !== 100) {
					additionalIEZoom = zoom / 100
				}
			}
		}

		if (additionalIEZoom !== 1) {
			svgPoint.x = svgPoint.x * additionalIEZoom;
			svgPoint.y = svgPoint.y * additionalIEZoom;
		}

		var matrix = canvas.node.getScreenCTM();
		return svgPoint.matrixTransform(matrix.inverse());
	}
};
ORYX.Editor = Clazz.extend(ORYX.Editor);

/**
 * Creates a new ORYX.Editor instance by fetching a model from given url and
 * passing it to the constructur
 * 
 * @param {String}
 *            modelUrl The JSON URL of a model.
 * @param {Object}
 *            config Editor config passed to the constructur, merged with the
 *            response of the request to modelUrl
 */
ORYX.Editor.createByUrl = function(modelUrl) {
	new Ajax.Request(modelUrl, {
				method : 'GET',
				onSuccess : function(transport) {
					var editorConfig = JSON.parse(transport.responseText);
					new ORYX.Editor(editorConfig);
				}.bind(this)
			});
}

// TODO Implement namespace awareness on attribute level.
/**
 * graft() function Originally by Sean M. Burke from interglacial.com, altered
 * for usage with SVG and namespace (xmlns) support. Be sure you understand
 * xmlns before using this funtion, as it creates all grafted elements in the
 * xmlns provided by you and all element's attribures in default xmlns. If you
 * need to graft elements in a certain xmlns and wish to assign attributes in
 * both that and another xmlns, you will need to do stepwise grafting, adding
 * non-default attributes yourself or you'll have to enhance this function.
 * Latter, I would appreciate: martin???apfelfabrik.de
 * 
 * @param {Object}
 *            namespace The namespace in which elements should be grafted.
 * @param {Object}
 *            parent The element that should contain the grafted structure after
 *            the function returned.
 * @param {Object}
 *            t the crafting structure.
 * @param {Object}
 *            doc the document in which grafting is performed.
 */
ORYX.Editor.graft = function(namespace, parent, t, doc) {

	doc = (doc || (parent && parent.ownerDocument) || document);
	var e;
	if (t === undefined) {
		throw "Can't graft an undefined value";
	} else if (t.constructor == String) {
		e = doc.createTextNode(t);
	} else {
		for (var i = 0; i < t.length; i++) {
			if (i === 0 && t[i].constructor == String) {
				var snared;
				snared = t[i].match(/^([a-z][a-z0-9]*)\.([^\s\.]+)$/i);
				if (snared) {
					e = doc.createElementNS(namespace, snared[1]);
					e.setAttributeNS(null, 'class', snared[2]);
					continue;
				}
				snared = t[i].match(/^([a-z][a-z0-9]*)$/i);
				if (snared) {
					e = doc.createElementNS(namespace, snared[1]); // but no
																	// class
					continue;
				}

				// Otherwise:
				e = doc.createElementNS(namespace, "span");
				e.setAttribute(null, "class", "namelessFromLOL");
			}

			if (t[i] === undefined) {
				throw "Can't graft an undefined value in a list!";
			} else if (t[i].constructor == String || t[i].constructor == Array) {
				this.graft(namespace, e, t[i], doc);
			} else if (t[i].constructor == Number) {
				this.graft(namespace, e, t[i].toString(), doc);
			} else if (t[i].constructor == Object) {
				// hash's properties => element's attributes
				for (var k in t[i]) {
					e.setAttributeNS(null, k, t[i][k]);
				}
			} else {

			}
		}
	}
	if (parent && parent.appendChild) {
		parent.appendChild(e);
	} else {

	}
	return e; // return the topmost created node
};

ORYX.Editor.provideId = function() {
	var res = [], hex = '0123456789ABCDEF';

	for (var i = 0; i < 36; i++)
		res[i] = Math.floor(Math.random() * 0x10);

	res[14] = 4;
	res[19] = (res[19] & 0x3) | 0x8;

	for (var i = 0; i < 36; i++)
		res[i] = hex[res[i]];

	res[8] = res[13] = res[18] = res[23] = '-';

	return "oryx_" + res.join('');
};

/**
 * When working with Ext, conditionally the window needs to be resized. To do
 * so, use this class method. Resize is deferred until 100ms, and all subsequent
 * resizeBugFix calls are ignored until the initially requested resize is
 * performed.
 */
ORYX.Editor.resizeFix = function() {
	if (!ORYX.Editor._resizeFixTimeout) {
		ORYX.Editor._resizeFixTimeout = window.setTimeout(function() {
					window.resizeBy(1, 1);
					window.resizeBy(-1, -1);
					ORYX.Editor._resizefixTimeout = null;
				}, 100);
	}
};

ORYX.Editor.Cookie = {

	callbacks : [],

	onChange : function(callback, interval) {

		this.callbacks.push(callback);
		this.start(interval)

	},

	start : function(interval) {

		if (this.pe) {
			return;
		}

		var currentString = document.cookie;

		this.pe = new PeriodicalExecuter(function() {

					if (currentString != document.cookie) {
						currentString = document.cookie;
						this.callbacks.each(function(callback) {
									callback(this.getParams())
								}.bind(this));
					}

				}.bind(this), (interval || 10000) / 1000);
	},

	stop : function() {

		if (this.pe) {
			this.pe.stop();
			this.pe = null;
		}
	},

	getParams : function() {
		var res = {};

		var p = document.cookie;
		p.split("; ").each(function(param) {
					res[param.split("=")[0]] = param.split("=")[1];
				});

		return res;
	},

	toString : function() {
		return document.cookie;
	}
};

/**
 * Workaround for SAFARI/Webkit, because when trying to check SVGSVGElement of
 * instanceof there is raising an error
 * 
 */
ORYX.Editor.SVGClassElementsAreAvailable = true;
ORYX.Editor.setMissingClasses = function() {

	try {
		SVGElement;
	} catch (e) {
		ORYX.Editor.SVGClassElementsAreAvailable = false;
		SVGSVGElement = document.createElementNS('http://www.w3.org/2000/svg',
				'svg').toString();
		SVGGElement = document.createElementNS('http://www.w3.org/2000/svg',
				'g').toString();
		SVGPathElement = document.createElementNS('http://www.w3.org/2000/svg',
				'path').toString();
		SVGTextElement = document.createElementNS('http://www.w3.org/2000/svg',
				'text').toString();
		// SVGMarkerElement =
		// document.createElementNS('http://www.w3.org/2000/svg',
		// 'marker').toString();
		SVGRectElement = document.createElementNS('http://www.w3.org/2000/svg',
				'rect').toString();
		SVGImageElement = document.createElementNS(
				'http://www.w3.org/2000/svg', 'image').toString();
		SVGCircleElement = document.createElementNS(
				'http://www.w3.org/2000/svg', 'circle').toString();
		SVGEllipseElement = document.createElementNS(
				'http://www.w3.org/2000/svg', 'ellipse').toString();
		SVGLineElement = document.createElementNS('http://www.w3.org/2000/svg',
				'line').toString();
		SVGPolylineElement = document.createElementNS(
				'http://www.w3.org/2000/svg', 'polyline').toString();
		SVGPolygonElement = document.createElementNS(
				'http://www.w3.org/2000/svg', 'polygon').toString();

	}

}
ORYX.Editor.checkClassType = function(classInst, classType) {

	if (ORYX.Editor.SVGClassElementsAreAvailable) {
		return classInst instanceof classType
	} else {
		return classInst == classType
	}
};
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}

new function() {

	ORYX.Core.UIEnableDrag = function(event, uiObj, option) {

		this.uiObj = uiObj;
		var upL = uiObj.bounds.upperLeft();

		var a = uiObj.node.getScreenCTM();
		this.faktorXY = {
			x : a.a,
			y : a.d
		};

		this.scrollNode = uiObj.node.ownerSVGElement.parentNode.parentNode;

		this.offSetPosition = {
			x : Event.pointerX(event) - (upL.x * this.faktorXY.x),
			y : Event.pointerY(event) - (upL.y * this.faktorXY.y)
		};

		this.offsetScroll = {
			x : this.scrollNode.scrollLeft,
			y : this.scrollNode.scrollTop
		};

		this.dragCallback = ORYX.Core.UIDragCallback.bind(this);
		this.disableCallback = ORYX.Core.UIDisableDrag.bind(this);

		this.movedCallback = option ? option.movedCallback : undefined;
		this.upCallback = option ? option.upCallback : undefined;

		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP,
				this.disableCallback, true);
		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE,
				this.dragCallback, false);

	};

	ORYX.Core.UIDragCallback = function(event) {

		var position = {
			x : Event.pointerX(event) - this.offSetPosition.x,
			y : Event.pointerY(event) - this.offSetPosition.y
		}

		position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft;
		position.y -= this.offsetScroll.y - this.scrollNode.scrollTop;

		position.x /= this.faktorXY.x;
		position.y /= this.faktorXY.y;

		this.uiObj.bounds.moveTo(position);
		// this.uiObj.update();

		if (this.movedCallback)
			this.movedCallback(event);

		// Event.stop(event);

	};

	ORYX.Core.UIDisableDrag = function(event) {
		document.documentElement.removeEventListener(
				ORYX.CONFIG.EVENT_MOUSEMOVE, this.dragCallback, false);
		document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEUP,
				this.disableCallback, true);

		if (this.upCallback)
			this.upCallback(event);

		this.upCallback = undefined;
		this.movedCallback = undefined;

		Event.stop(event);
	};

	/**
	 * Implements a command to move docker by an offset.
	 * 
	 * @class ORYX.Core.MoveDockersCommand
	 * @param {Object}
	 *            object An object with the docker id as key and docker and
	 *            offset as object value
	 * 
	 */
	ORYX.Core.MoveDockersCommand = ORYX.Core.Command.extend({
		construct : function(dockers) {
			this.dockers = $H(dockers);
			this.edges = $H({});
		},
		execute : function() {
			if (this.changes) {
				this.executeAgain();
				return;
			} else {
				this.changes = $H({});
			}

			this.dockers.values().each(function(docker) {
						var edge = docker.docker.parent;
						if (!edge) {
							return
						}

						if (!this.changes[edge.getId()]) {
							this.changes[edge.getId()] = {
								edge : edge,
								oldDockerPositions : edge.dockers.map(function(
												r) {
											return r.bounds.center()
										})
							}
						}
						docker.docker.bounds.moveBy(docker.offset);
						this.edges[edge.getId()] = edge;
						docker.docker.update();
					}.bind(this));
			this.edges.each(function(edge) {
				this.updateEdge(edge.value);
				if (this.changes[edge.value.getId()])
					this.changes[edge.value.getId()].dockerPositions = edge.value.dockers
							.map(function(r) {
										return r.bounds.center()
									})
			}.bind(this));
		},
		updateEdge : function(edge) {
			edge._update(true);
			[edge.getOutgoingShapes(), edge.getIncomingShapes()].flatten()
					.invoke("_update", [true])
		},
		executeAgain : function() {
			this.changes.values().each(function(change) {
				// Reset the dockers
				this.removeAllDocker(change.edge);
				change.dockerPositions.each(function(pos, i) {
							if (i == 0
									|| i == change.dockerPositions.length - 1) {
								return
							}
							var docker = change.edge.createDocker(undefined,
									pos);
							docker.bounds.centerMoveTo(pos);
							docker.update();
						}.bind(this));
				this.updateEdge(change.edge);
			}.bind(this));
		},
		rollback : function() {
			this.changes.values().each(function(change) {
				// Reset the dockers
				this.removeAllDocker(change.edge);
				change.oldDockerPositions.each(function(pos, i) {
							if (i == 0
									|| i == change.oldDockerPositions.length
											- 1) {
								return
							}
							var docker = change.edge.createDocker(undefined,
									pos);
							docker.bounds.centerMoveTo(pos);
							docker.update();
						}.bind(this));
				this.updateEdge(change.edge);
			}.bind(this));
		},
		removeAllDocker : function(edge) {
			edge.dockers.slice(1, edge.dockers.length - 1).each(
					function(docker) {
						edge.removeDocker(docker);
					})
		}
	});

}();
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}

/**
 * @classDescription Base class for Shapes.
 * @extends ORYX.Core.AbstractShape
 */
ORYX.Core.Shape = {

	/**
	 * Constructor
	 */
	construct : function(options, stencil, facade) {
		// call base class constructor
		arguments.callee.$.construct.apply(this, arguments);

		this.facade = facade;
		this.dockers = [];
		this.magnets = [];

		this._defaultMagnet;

		this.incoming = [];
		this.outgoing = [];

		this.nodes = [];

		this._dockerChangedCallback = this._dockerChanged.bind(this);

		// Hash map for all labels. Labels are not treated as children of
		// shapes.
		this._labels = new Hash();

		// create SVG node
		this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", null, ['g',
						{
							id : "svg-" + this.resourceId
						}, ['g', {
									"class" : "stencils"
								}, ['g', {
											"class" : "me"
										}], ['g', {
											"class" : "children",
											style : "overflow:hidden"
										}], ['g', {
											"class" : "edge"
										}]], ['g', {
									"class" : "controls"
								}, ['g', {
											"class" : "dockers"
										}], ['g', {
											"class" : "magnets"
										}]]]);
	},

	/**
	 * If changed flag is set, refresh method is called.
	 */
	update : function() {
		// if(this.isChanged) {
		// this.layout();
		// }
	},

	/**
	 * !!!Not called from any sub class!!!
	 */
	_update : function() {

	},

	/**
	 * Calls the super class refresh method and updates the svg elements that
	 * are referenced by a property.
	 */
	refresh : function() {
		// call base class refresh method
		arguments.callee.$.refresh.apply(this, arguments);

		if (this.node.ownerDocument) {
			// adjust SVG to properties' values
			var me = this;
			this.propertiesChanged.each((function(propChanged) {
				if (propChanged.value) {
					var prop = this.properties[propChanged.key];
					var property = this.getStencil().property(propChanged.key);
					if (property != undefined) {
						this.propertiesChanged[propChanged.key] = false;

						// handle choice properties
						if (property.type() == ORYX.CONFIG.TYPE_CHOICE) {
							// iterate all references to SVG elements
							property.refToView().each((function(ref) {
								// if property is referencing a label, update
								// the label
								if (ref !== "") {
									var label = this._labels[this.id + ref];
									if (label && property.item(prop)) {
										label.text(property.item(prop).title());
									}
								}
							}).bind(this));

							// if the choice's items are referencing SVG
							// elements
							// show the selected and hide all other referenced
							// SVG
							// elements
							var refreshedSvgElements = new Hash();
							property.items().each((function(item) {
								item.refToView().each((function(itemRef) {
									if (itemRef == "") {
										return;
									}

									var svgElem = this.node.ownerDocument
											.getElementById(this.id + itemRef);

									if (!svgElem) {
										return;
									}

									/*
									 * Do not refresh the same svg element
									 * multiple times
									 */
									if (!refreshedSvgElements[svgElem.id]
											|| prop == item.value()) {
										svgElem.setAttributeNS(null, 'display',
												((prop == item.value())
														? 'inherit'
														: 'none'));
										refreshedSvgElements[svgElem.id] = svgElem;
									}

									// Reload the href if there is an image-tag
									if (ORYX.Editor.checkClassType(svgElem,
											SVGImageElement)) {
										svgElem
												.setAttributeNS(
														'http://www.w3.org/1999/xlink',
														'href',
														svgElem
																.getAttributeNS(
																		'http://www.w3.org/1999/xlink',
																		'href'));
									}
								}).bind(this));
							}).bind(this));

						} else { // handle properties that are not of type
									// choice
							// iterate all references to SVG elements
							property.refToView().each((function(ref) {
								// if the property does not reference an SVG
								// element,
								// do nothing

								if (ref === "") {
									return;
								}

								var refId = this.id + ref;

								if (property.type() === ORYX.CONFIG.TYPE_KISBPM_MULTIINSTANCE) {
									if (ref === "multiinstance") {

										var svgElemParallel = this.node.ownerDocument
												.getElementById(this.id
														+ 'parallel');
										if (svgElemParallel) {
											if (prop === 'Parallel') {
												svgElemParallel.setAttributeNS(
														null, 'display',
														'inherit');
											} else {
												svgElemParallel
														.setAttributeNS(null,
																'display',
																'none');
											}
										}

										var svgElemSequential = this.node.ownerDocument
												.getElementById(this.id
														+ 'sequential');

										if (svgElemSequential) {
											if (prop === 'Sequential') {
												svgElemSequential
														.setAttributeNS(null,
																'display',
																'inherit');
											} else {
												svgElemSequential
														.setAttributeNS(null,
																'display',
																'none');
											}
										}
									}
									return;

								} else if (property.type() === "cancelactivity") {
									var svgElemFrame = this.node.ownerDocument
											.getElementById(this.id + 'frame');
									var svgElemFrame2 = this.node.ownerDocument
											.getElementById(this.id + 'frame2');

									if (prop === 'true') {
										svgElemFrame.setAttributeNS(null,
												'display', 'inherit');
										svgElemFrame2.setAttributeNS(null,
												'display', 'inherit');
									} else {
										svgElemFrame.setAttributeNS(null,
												'display', 'none');
										svgElemFrame2.setAttributeNS(null,
												'display', 'none');
									}
								}

								// get the SVG element
								var svgElem = this.node.ownerDocument
										.getElementById(refId);

								// if the SVG element can not be found
								if (!svgElem || !(svgElem.ownerSVGElement)) {
									// if the referenced SVG element is a
									// SVGAElement, it cannot
									// be found with getElementById (Firefox
									// bug).
									// this is a work around
									if (property.type() === ORYX.CONFIG.TYPE_URL
											|| property.type() === ORYX.CONFIG.TYPE_DIAGRAM_LINK) {
										var svgElems = this.node.ownerDocument
												.getElementsByTagNameNS(
														'http://www.w3.org/2000/svg',
														'a');

										svgElem = $A(svgElems).find(
												function(elem) {
													return elem.getAttributeNS(
															null, 'id') === refId;
												});

										if (!svgElem) {
											return;
										}
									} else {
										// this.propertiesChanged[propChanged.key]
										// = true;
										return;
									}
								}

								if (property.complexAttributeToView()) {
									var label = this._labels[refId];
									if (label) {
										try {
											propJson = prop.evalJSON();
											var value = propJson[property
													.complexAttributeToView()]
											label.text(value ? value : prop);
										} catch (e) {
											label.text(prop);
										}
									}

								} else {
									switch (property.type()) {
										case ORYX.CONFIG.TYPE_BOOLEAN :
											if (typeof prop == "string")
												prop = prop === "true"

											svgElem.setAttributeNS(null,
													'display',
													(!(prop === property
															.inverseBoolean()))
															? 'inherit'
															: 'none');

											break;
										case ORYX.CONFIG.TYPE_COLOR :
											if (property.fill()) {
												if (svgElem.tagName
														.toLowerCase() === "stop") {
													if (prop) {

														if (property
																.lightness()
																&& property
																		.lightness() !== 1) {
															prop = ORYX.Utils
																	.adjustLightness(
																			prop,
																			property
																					.lightness());
														}

														svgElem.setAttributeNS(
																null,
																"stop-color",
																prop);

														// Adjust stop color of
														// the others
														if (svgElem.parentNode.tagName
																.toLowerCase() === "radialgradient") {
															ORYX.Utils
																	.adjustGradient(
																			svgElem.parentNode,
																			svgElem);
														}
													}

													// If there is no value, set
													// opaque
													if (svgElem.parentNode.tagName
															.toLowerCase() === "radialgradient") {
														$A(svgElem.parentNode
																.getElementsByTagName('stop'))
																.each(
																		function(
																				stop) {
																			stop
																					.setAttributeNS(
																							null,
																							"stop-opacity",
																							prop
																									? stop
																											.getAttributeNS(
																													ORYX.CONFIG.NAMESPACE_ORYX,
																													'default-stop-opacity')
																											|| 1
																									: 0);
																		}
																				.bind(this))
													}
												} else {
													svgElem.setAttributeNS(
															null, 'fill', prop);
												}
											}
											if (property.stroke()) {
												svgElem.setAttributeNS(null,
														'stroke', prop);
											}
											break;
										case ORYX.CONFIG.TYPE_STRING :
											var label = this._labels[refId];
											if (label) {
												label.text(prop);
											}
											break;
										case ORYX.CONFIG.TYPE_EXPRESSION :
											var label = this._labels[refId];
											if (label) {
												label.text(prop);
											}
											break;
										case ORYX.CONFIG.TYPE_DATASOURCE :
											var label = this._labels[refId];
											if (label) {
												label.text(prop);
											}
											break;
										case ORYX.CONFIG.TYPE_INTEGER :
											var label = this._labels[refId];
											if (label) {
												label.text(prop);
											}
											break;
										case ORYX.CONFIG.TYPE_FLOAT :
											if (property.fillOpacity()) {
												svgElem.setAttributeNS(null,
														'fill-opacity', prop);
											}
											if (property.strokeOpacity()) {
												svgElem.setAttributeNS(null,
														'stroke-opacity', prop);
											}
											if (!property.fillOpacity()
													&& !property
															.strokeOpacity()) {
												var label = this._labels[refId];
												if (label) {
													label.text(prop);
												}
											}
											break;

										case ORYX.CONFIG.TYPE_FORM_LINK :
											if (ref == "pimg") {
												var onclickAttr = svgElem
														.getAttributeNodeNS('',
																'onclick');
												if (onclickAttr) {
													if (prop
															&& ("" + prop).length > 0) {
														onclickAttr.textContent = "window.location = '../service/editor?id="
																+ prop
																+ "_form'";
													} else {
														newFormFacade = this.facade;
														onclickAttr.textContent = "displayNewFormDialog('"
																+ this.resourceId
																+ "');";
													}
												}
											} else if (ref == "linkIndicator") {
												if (prop && prop.length > 0) {
													svgElem.setAttributeNS(
															null, 'display',
															'inherit');
												} else {
													svgElem.setAttributeNS(
															null, 'display',
															'none');
												}
											}
											break;
										case ORYX.CONFIG.TYPE_URL :
										case ORYX.CONFIG.TYPE_DIAGRAM_LINK :
											// TODO what is the dafault path?
											var hrefAttr = svgElem
													.getAttributeNodeNS(
															'http://www.w3.org/1999/xlink',
															'xlink:href');
											if (hrefAttr) {
												hrefAttr.textContent = prop;
											} else {
												svgElem
														.setAttributeNS(
																'http://www.w3.org/1999/xlink',
																'xlink:href',
																prop);
											}
											break;

									}
								}
							}).bind(this));

						}
					}

				}
			}).bind(this));

			// update labels
			this._labels.values().each(function(label) {
						label.update();
					});
		}
	},

	layout : function() {
		// this.getStencil().layout(this)
		var layoutEvents = this.getStencil().layout()
		if (layoutEvents) {
			layoutEvents.each(function(event) {

						// setup additional attributes
						event.shape = this;
						event.forceExecution = true;

						// do layouting
						this._delegateEvent(event);
					}.bind(this))

		}
	},

	/**
	 * Returns an array of Label objects.
	 */
	getLabels : function() {
		return this._labels.values();
	},

	/**
	 * Returns the label for a given ref
	 * 
	 * @return {ORYX.Core.Label} Returns null if there is no label
	 */
	getLabel : function(ref) {
		if (!ref) {
			return null;
		}
		return (this._labels.find(function(o) {
					return o.key.endsWith(ref);
				}) || {}).value || null;
	},

	/**
	 * Hides all related labels
	 * 
	 */
	hideLabels : function() {
		this.getLabels().invoke("hide");
	},

	/**
	 * Shows all related labels
	 * 
	 */
	showLabels : function() {
		var labels = this.getLabels();
		labels.invoke("show");
		labels.each(function(label) {
					label.update();
				});
	},

	setOpacity : function(value, animate) {

		value = Math.max(Math
						.min((typeof value == "number" ? value : 1.0), 1.0),
				0.0);

		if (value !== 1.0) {
			value = String(value);
			this.node.setAttributeNS(null, "fill-opacity", value)
			this.node.setAttributeNS(null, "stroke-opacity", value)
		} else {
			this.node.removeAttributeNS(null, "fill-opacity");
			this.node.removeAttributeNS(null, "stroke-opacity");
		}
	},

	/**
	 * Returns an array of dockers of this object.
	 */
	getDockers : function() {
		return this.dockers;
	},

	getMagnets : function() {
		return this.magnets;
	},

	getDefaultMagnet : function() {
		if (this._defaultMagnet) {
			return this._defaultMagnet;
		} else if (this.magnets.length > 0) {
			return this.magnets[0];
		} else {
			return undefined;
		}
	},

	getParentShape : function() {
		return this.parent;
	},

	getIncomingShapes : function(iterator) {
		if (iterator) {
			this.incoming.each(iterator);
		}
		return this.incoming;
	},

	getIncomingNodes : function(iterator) {
		return this.incoming.select(function(incoming) {
					var isNode = (incoming instanceof ORYX.Core.Node);
					if (isNode && iterator)
						iterator(incoming);
					return isNode;
				});
	},

	getOutgoingShapes : function(iterator) {
		if (iterator) {
			this.outgoing.each(iterator);
		}
		return this.outgoing;
	},

	getOutgoingNodes : function(iterator) {
		return this.outgoing.select(function(out) {
					var isNode = (out instanceof ORYX.Core.Node);
					if (isNode && iterator)
						iterator(out);
					return isNode;
				});
	},

	getAllDockedShapes : function(iterator) {
		var result = this.incoming.concat(this.outgoing);
		if (iterator) {
			result.each(iterator);
		}
		return result
	},

	getCanvas : function() {
		if (this.parent instanceof ORYX.Core.Canvas) {
			return this.parent;
		} else if (this.parent instanceof ORYX.Core.Shape) {
			return this.parent.getCanvas();
		} else {
			return undefined;
		}
	},

	/**
	 * 
	 * @param {Object}
	 *            deep
	 * @param {Object}
	 *            iterator
	 */
	getChildNodes : function(deep, iterator) {
		if (!deep && !iterator) {
			return this.nodes.clone();
		} else {
			var result = [];
			this.nodes.each(function(uiObject) {
						if (!uiObject.isVisible) {
							return
						}
						if (iterator) {
							iterator(uiObject);
						}
						result.push(uiObject);

						if (deep && uiObject instanceof ORYX.Core.Shape) {
							result = result.concat(uiObject.getChildNodes(deep,
									iterator));
						}
					});

			return result;
		}
	},

	/**
	 * Overrides the UIObject.add method. Adds uiObject to the correct sub node.
	 * 
	 * @param {UIObject}
	 *            uiObject
	 * @param {Number}
	 *            index
	 */
	add : function(uiObject, index, silent) {
		// parameter has to be an UIObject, but
		// must not be an Edge.
		if (uiObject instanceof ORYX.Core.UIObject
				&& !(uiObject instanceof ORYX.Core.Edge)) {

			if (!(this.children.member(uiObject))) {
				// if uiObject is child of another parent, remove it from that
				// parent.
				if (uiObject.parent) {
					uiObject.parent.remove(uiObject, true);
				}

				// add uiObject to this Shape
				if (index != undefined)
					this.children.splice(index, 0, uiObject);
				else
					this.children.push(uiObject);

				// set parent reference
				uiObject.parent = this;

				// add uiObject.node to this.node depending on the type of
				// uiObject
				var parent;
				if (uiObject instanceof ORYX.Core.Node) {
					parent = this.node.childNodes[0].childNodes[1];
					this.nodes.push(uiObject);
				} else if (uiObject instanceof ORYX.Core.Controls.Control) {
					var ctrls = this.node.childNodes[1];
					if (uiObject instanceof ORYX.Core.Controls.Docker) {
						parent = ctrls.childNodes[0];
						if (this.dockers.length >= 2) {
							this.dockers.splice(index !== undefined
											? Math.min(index,
													this.dockers.length - 1)
											: this.dockers.length - 1, 0,
									uiObject);
						} else {
							this.dockers.push(uiObject);
						}
					} else if (uiObject instanceof ORYX.Core.Controls.Magnet) {
						parent = ctrls.childNodes[1];
						this.magnets.push(uiObject);
					} else {
						parent = ctrls;
					}
				} else { // UIObject
					parent = this.node;
				}

				if (index != undefined && index < parent.childNodes.length)
					uiObject.node = parent.insertBefore(uiObject.node,
							parent.childNodes[index]);
				else
					uiObject.node = parent.appendChild(uiObject.node);

				this._changed();
				// uiObject.bounds.registerCallback(this._changedCallback);

				if (this.eventHandlerCallback && silent !== true)
					this.eventHandlerCallback({
								type : ORYX.CONFIG.EVENT_SHAPEADDED,
								shape : uiObject
							})

			} else {

				ORYX.Log
						.warn("add: ORYX.Core.UIObject is already a child of this object.");
			}
		} else {

			ORYX.Log.warn("add: Parameter is not of type ORYX.Core.UIObject.");
		}
	},

	/**
	 * Overrides the UIObject.remove method. Removes uiObject.
	 * 
	 * @param {UIObject}
	 *            uiObject
	 */
	remove : function(uiObject, silent) {
		// if uiObject is a child of this object, remove it.
		if (this.children.member(uiObject)) {
			// remove uiObject from children
			var parent = uiObject.parent;

			this.children = this.children.without(uiObject);

			// delete parent reference of uiObject
			uiObject.parent = undefined;

			// delete uiObject.node from this.node
			if (uiObject instanceof ORYX.Core.Shape) {
				if (uiObject instanceof ORYX.Core.Edge) {
					uiObject.removeMarkers();
					uiObject.node = this.node.childNodes[0].childNodes[2]
							.removeChild(uiObject.node);
				} else {
					uiObject.node = this.node.childNodes[0].childNodes[1]
							.removeChild(uiObject.node);
					this.nodes = this.nodes.without(uiObject);
				}
			} else if (uiObject instanceof ORYX.Core.Controls.Control) {
				if (uiObject instanceof ORYX.Core.Controls.Docker) {
					uiObject.node = this.node.childNodes[1].childNodes[0]
							.removeChild(uiObject.node);
					this.dockers = this.dockers.without(uiObject);
				} else if (uiObject instanceof ORYX.Core.Controls.Magnet) {
					uiObject.node = this.node.childNodes[1].childNodes[1]
							.removeChild(uiObject.node);
					this.magnets = this.magnets.without(uiObject);
				} else {
					uiObject.node = this.node.childNodes[1]
							.removeChild(uiObject.node);
				}
			}

			if (this.eventHandlerCallback && silent !== true)
				this.eventHandlerCallback({
							type : ORYX.CONFIG.EVENT_SHAPEREMOVED,
							shape : uiObject,
							parent : parent
						});

			this._changed();
			// uiObject.bounds.unregisterCallback(this._changedCallback);
		} else {

			ORYX.Log
					.warn("remove: ORYX.Core.UIObject is not a child of this object.");
		}
	},

	/**
	 * Calculate the Border Intersection Point between two points
	 * 
	 * @param {PointA}
	 * @param {PointB}
	 */
	getIntersectionPoint : function() {

		var pointAX, pointAY, pointBX, pointBY;

		// Get the the two Points
		switch (arguments.length) {
			case 2 :
				pointAX = arguments[0].x;
				pointAY = arguments[0].y;
				pointBX = arguments[1].x;
				pointBY = arguments[1].y;
				break;
			case 4 :
				pointAX = arguments[0];
				pointAY = arguments[1];
				pointBX = arguments[2];
				pointBY = arguments[3];
				break;
			default :
				throw "getIntersectionPoints needs two or four arguments";
		}

		// Defined an include and exclude point
		var includePointX, includePointY, excludePointX, excludePointY;

		var bounds = this.absoluteBounds();

		if (this.isPointIncluded(pointAX, pointAY, bounds)) {
			includePointX = pointAX;
			includePointY = pointAY;
		} else {
			excludePointX = pointAX;
			excludePointY = pointAY;
		}

		if (this.isPointIncluded(pointBX, pointBY, bounds)) {
			includePointX = pointBX;
			includePointY = pointBY;
		} else {
			excludePointX = pointBX;
			excludePointY = pointBY;
		}

		// If there is no inclue or exclude Shape, than return
		if (!includePointX || !includePointY || !excludePointX
				|| !excludePointY) {
			return undefined;
		}

		var midPointX = 0;
		var midPointY = 0;

		var refPointX, refPointY;

		var minDifferent = 1;
		// Get the UpperLeft and LowerRight
		// var ul = bounds.upperLeft();
		// var lr = bounds.lowerRight();

		var i = 0;

		while (true) {
			// Calculate the midpoint of the current to points
			var midPointX = Math.min(includePointX, excludePointX)
					+ ((Math.max(includePointX, excludePointX) - Math.min(
							includePointX, excludePointX)) / 2.0);
			var midPointY = Math.min(includePointY, excludePointY)
					+ ((Math.max(includePointY, excludePointY) - Math.min(
							includePointY, excludePointY)) / 2.0);

			// Set the new midpoint by the means of the include of the bounds
			if (this.isPointIncluded(midPointX, midPointY, bounds)) {
				includePointX = midPointX;
				includePointY = midPointY;
			} else {
				excludePointX = midPointX;
				excludePointY = midPointY;
			}

			// Calc the length of the line
			var length = Math.sqrt(Math.pow(includePointX - excludePointX, 2)
					+ Math.pow(includePointY - excludePointY, 2))
			// Calc a point one step from the include point
			refPointX = includePointX
					+ ((excludePointX - includePointX) / length), refPointY = includePointY
					+ ((excludePointY - includePointY) / length)

			// If the reference point not in the bounds, break
			if (!this.isPointIncluded(refPointX, refPointY, bounds)) {
				break
			}

		}

		// Return the last includepoint
		return {
			x : refPointX,
			y : refPointY
		};
	},

	/**
	 * Calculate if the point is inside the Shape
	 * 
	 * @param {PointX}
	 * @param {PointY}
	 */
	isPointIncluded : function() {
		return false
	},

	/**
	 * Returns TRUE if the given node is a child node of the shapes node
	 * 
	 * @param {Element}
	 *            node
	 * @return {Boolean}
	 * 
	 */
	containsNode : function(node) {
		var me = this.node.firstChild.firstChild;
		while (node) {
			if (node == me) {
				return true;
			}
			node = node.parentNode;
		}
		return false
	},

	/**
	 * Calculate if the point is over an special offset area
	 * 
	 * @param {Point}
	 */
	isPointOverOffset : function() {
		return this.isPointIncluded.apply(this, arguments)
	},

	_dockerChanged : function() {

	},

	/**
	 * Create a Docker for this Edge
	 * 
	 */
	createDocker : function(index, position) {
		var docker = new ORYX.Core.Controls.Docker({
					eventHandlerCallback : this.eventHandlerCallback
				});
		docker.bounds.registerCallback(this._dockerChangedCallback);
		if (position) {
			docker.bounds.centerMoveTo(position);
		}
		this.add(docker, index);

		return docker
	},

	/**
	 * Get the serialized object return Array with hash-entrees (prefix, name,
	 * value) Following values will given: Bounds Outgoing Shapes Parent
	 */
	serialize : function() {
		var serializedObject = arguments.callee.$.serialize.apply(this);

		// Add the bounds
		serializedObject.push({
					name : 'bounds',
					prefix : 'oryx',
					value : this.bounds.serializeForERDF(),
					type : 'literal'
				});

		// Add the outgoing shapes
		this.getOutgoingShapes().each((function(followingShape) {
			serializedObject.push({
						name : 'outgoing',
						prefix : 'raziel',
						value : '#'
								+ ERDF.__stripHashes(followingShape.resourceId),
						type : 'resource'
					});
		}).bind(this));

		// Add the parent shape, if the parent not the canvas
		// if(this.parent instanceof ORYX.Core.Shape){
		serializedObject.push({
					name : 'parent',
					prefix : 'raziel',
					value : '#' + ERDF.__stripHashes(this.parent.resourceId),
					type : 'resource'
				});
		// }

		return serializedObject;
	},

	deserialize : function(serialize, json) {
		arguments.callee.$.deserialize.apply(this, arguments);

		// Set the Bounds
		var bounds = serialize.find(function(ser) {
					return 'oryx-bounds' === (ser.prefix + "-" + ser.name)
				});
		if (bounds) {
			var b = bounds.value.replace(/,/g, " ").split(" ").without("");
			if (this instanceof ORYX.Core.Edge) {
				if (!this.dockers.first().isChanged)
					this.dockers.first().bounds.centerMoveTo(parseFloat(b[0]),
							parseFloat(b[1]));
				if (!this.dockers.last().isChanged)
					this.dockers.last().bounds.centerMoveTo(parseFloat(b[2]),
							parseFloat(b[3]));
			} else {
				this.bounds.set(parseFloat(b[0]), parseFloat(b[1]),
						parseFloat(b[2]), parseFloat(b[3]));
			}
		}

		if (json && json.labels instanceof Array) {
			json.labels.each(function(slabel) {
						var label = this.getLabel(slabel.ref);
						if (label) {
							label.deserialize(slabel, this);
						}
					}.bind(this))
		}
	},

	toJSON : function() {
		var json = arguments.callee.$.toJSON.apply(this, arguments);

		var labels = [], id = this.id;
		this._labels.each(function(obj) {
					var slabel = obj.value.serialize();
					if (slabel) {
						slabel.ref = obj.key.replace(id, '');
						labels.push(slabel);
					}
				});

		if (labels.length > 0) {
			json.labels = labels;
		}
		return json;
	},

	/**
	 * Private methods.
	 */

	/**
	 * Child classes have to overwrite this method for initializing a loaded SVG
	 * representation.
	 * 
	 * @param {SVGDocument}
	 *            svgDocument
	 */
	_init : function(svgDocument) {
		// adjust ids
		this._adjustIds(svgDocument, 0);
	},

	_adjustIds : function(element, idIndex) {
		if (element instanceof Element) {
			var eid = element.getAttributeNS(null, 'id');
			if (eid && eid !== "") {
				element.setAttributeNS(null, 'id', this.id + eid);
			} else {
				element.setAttributeNS(null, 'id', this.id + "_" + this.id
								+ "_" + idIndex);
				idIndex++;
			}

			// Replace URL in fill attribute
			var fill = element.getAttributeNS(null, 'fill');
			if (fill && fill.include("url(#")) {
				fill = fill.replace(/url\(#/g, 'url(#' + this.id);
				element.setAttributeNS(null, 'fill', fill);
			}

			if (element.hasChildNodes()) {
				for (var i = 0; i < element.childNodes.length; i++) {
					idIndex = this._adjustIds(element.childNodes[i], idIndex);
				}
			}
		}
		return idIndex;
	},

	toString : function() {
		return "ORYX.Core.Shape " + this.getId()
	}
};
ORYX.Core.Shape = ORYX.Core.AbstractShape.extend(ORYX.Core.Shape);/*
																	 * Copyright
																	 * 2005-2014
																	 * Alfresco
																	 * Software,
																	 * Ltd. All
																	 * rights
																	 * reserved.
																	 * License
																	 * rights
																	 * for this
																	 * program
																	 * may be
																	 * obtained
																	 * from
																	 * Alfresco
																	 * Software,
																	 * Ltd.
																	 * pursuant
																	 * to a
																	 * written
																	 * agreement
																	 * and any
																	 * use of
																	 * this
																	 * program
																	 * without
																	 * such an
																	 * agreement
																	 * is
																	 * prohibited.
																	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.Controls) {
	ORYX.Core.Controls = {};
}

/**
 * @classDescription Abstract base class for all Controls.
 */
ORYX.Core.Controls.Control = ORYX.Core.UIObject.extend({

			toString : function() {
				return "Control " + this.id;
			}
		});/*
			 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
			 * License rights for this program may be obtained from Alfresco
			 * Software, Ltd. pursuant to a written agreement and any use of
			 * this program without such an agreement is prohibited.
			 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.Controls) {
	ORYX.Core.Controls = {};
}

/**
 * @classDescription Represents a movable docker that can be bound to a shape.
 *                   Dockers are used for positioning shape objects.
 * @extends {Control}
 * 
 * TODO absoluteXY und absoluteCenterXY von einem Docker liefern falsche
 * Werte!!!
 */
ORYX.Core.Controls.Docker = ORYX.Core.Controls.Control.extend({
	/**
	 * Constructor
	 */
	construct : function() {
		arguments.callee.$.construct.apply(this, arguments);

		this.isMovable = true; // Enables movability
		this.bounds.set(0, 0, 16, 16); // Set the bounds
		this.referencePoint = undefined; // Refrenzpoint
		this._dockedShapeBounds = undefined;
		this._dockedShape = undefined;
		this._oldRefPoint1 = undefined;
		this._oldRefPoint2 = undefined;

		// this.anchors = [];
		this.anchorLeft;
		this.anchorRight;
		this.anchorTop;
		this.anchorBottom;

		this.node = ORYX.Editor
				.graft("http://www.w3.org/2000/svg", null, ['g']);

		// The DockerNode reprasentation
		this._dockerNode = ORYX.Editor.graft("http://www.w3.org/2000/svg",
				this.node, ['g', {
							"pointer-events" : "all"
						}, ['circle', {
									cx : "8",
									cy : "8",
									r : "8",
									stroke : "none",
									fill : "none"
								}], ['circle', {
									cx : "8",
									cy : "8",
									r : "3",
									stroke : "black",
									fill : "red",
									"stroke-width" : "1"
								}]]);

		// The ReferenzNode reprasentation
		this._referencePointNode = ORYX.Editor.graft(
				"http://www.w3.org/2000/svg", this.node, ['g', {
							"pointer-events" : "none"
						}, ['circle', {
									cx : this.bounds.upperLeft().x,
									cy : this.bounds.upperLeft().y,
									r : 3,
									fill : "red",
									"fill-opacity" : 0.4
								}]]);

		// Hide the Docker
		this.hide();

		// Add to the EventHandler
		this.addEventHandlers(this._dockerNode);

		// Buffer the Update Callback for un-/register on Event-Handler
		this._updateCallback = this._changed.bind(this);
	},

	update : function() {
		// If there have an DockedShape
		if (this._dockedShape) {
			if (this._dockedShapeBounds
					&& this._dockedShape instanceof ORYX.Core.Node) {
				// Calc the delta of width and height of the lastBounds and the
				// current Bounds
				var dswidth = this._dockedShapeBounds.width();
				var dsheight = this._dockedShapeBounds.height();
				if (!dswidth)
					dswidth = 1;
				if (!dsheight)
					dsheight = 1;
				var widthDelta = this._dockedShape.bounds.width() / dswidth;
				var heightDelta = this._dockedShape.bounds.height() / dsheight;

				// If there is an different
				if (widthDelta !== 1.0 || heightDelta !== 1.0) {
					// Set the delta
					this.referencePoint.x *= widthDelta;
					this.referencePoint.y *= heightDelta;
				}

				// Clone these bounds
				this._dockedShapeBounds = this._dockedShape.bounds.clone();
			}

			// Get the first and the last Docker of the parent Shape
			var dockerIndex = this.parent.dockers.indexOf(this)
			var dock1 = this;
			var dock2 = this.parent.dockers.length > 1 ? (dockerIndex === 0 ? // If
																				// there
																				// is
																				// the
																				// first
																				// element
					this.parent.dockers[dockerIndex + 1]
					: // then take the next docker
					this.parent.dockers[dockerIndex - 1]) : // if not, then take
															// the docker before
					undefined;

			// Calculate the first absolute Refenzpoint
			var absoluteReferenzPoint1 = dock1.getDockedShape() ? dock1
					.getAbsoluteReferencePoint() : dock1.bounds.center();

			// Calculate the last absolute Refenzpoint
			var absoluteReferenzPoint2 = dock2 && dock2.getDockedShape()
					? dock2.getAbsoluteReferencePoint()
					: dock2 ? dock2.bounds.center() : undefined;

			// If there is no last absolute Referenzpoint
			if (!absoluteReferenzPoint2) {
				// Calculate from the middle of the DockedShape
				var center = this._dockedShape.absoluteCenterXY();
				var minDimension = this._dockedShape.bounds.width()
						* this._dockedShape.bounds.height();
				absoluteReferenzPoint2 = {
					x : absoluteReferenzPoint1.x
							+ (center.x - absoluteReferenzPoint1.x)
							* -minDimension,
					y : absoluteReferenzPoint1.y
							+ (center.y - absoluteReferenzPoint1.y)
							* -minDimension
				}
			}

			var newPoint = undefined;

			/*
			 * if (!this._oldRefPoint1 || !this._oldRefPoint2 ||
			 * absoluteReferenzPoint1.x !== this._oldRefPoint1.x ||
			 * absoluteReferenzPoint1.y !== this._oldRefPoint1.y ||
			 * absoluteReferenzPoint2.x !== this._oldRefPoint2.x ||
			 * absoluteReferenzPoint2.y !== this._oldRefPoint2.y) {
			 */

			// Get the new point for the Docker, calucalted by the intersection
			// point of the Shape and the two points
			newPoint = this._dockedShape.getIntersectionPoint(
					absoluteReferenzPoint1, absoluteReferenzPoint2);

			// If there is new point, take the referencepoint as the new point
			if (!newPoint) {
				newPoint = this.getAbsoluteReferencePoint();
			}

			if (this.parent && this.parent.parent) {
				var grandParentPos = this.parent.parent.absoluteXY();
				newPoint.x -= grandParentPos.x;
				newPoint.y -= grandParentPos.y;
			}

			// Set the bounds to the new point
			this.bounds.centerMoveTo(newPoint)

			this._oldRefPoint1 = absoluteReferenzPoint1;
			this._oldRefPoint2 = absoluteReferenzPoint2;
		}
		/*
		 * else { newPoint = this.bounds.center(); }
		 */

		// }
		// Call the super class
		arguments.callee.$.update.apply(this, arguments);
	},

	/**
	 * Calls the super class refresh method and updates the view of the docker.
	 */
	refresh : function() {
		arguments.callee.$.refresh.apply(this, arguments);

		// Refresh the dockers node
		var p = this.bounds.upperLeft();
		this._dockerNode.setAttributeNS(null, 'transform', 'translate(' + p.x
						+ ', ' + p.y + ')');

		// Refresh the referencepoints node
		p = Object.clone(this.referencePoint);

		if (p && this._dockedShape) {
			var upL
			if (this.parent instanceof ORYX.Core.Edge) {
				upL = this._dockedShape.absoluteXY();
			} else {
				upL = this._dockedShape.bounds.upperLeft();
			}
			p.x += upL.x;
			p.y += upL.y;
		} else {
			p = this.bounds.center();
		}

		this._referencePointNode.setAttributeNS(null, 'transform', 'translate('
						+ p.x + ', ' + p.y + ')');
	},

	/**
	 * Set the reference point
	 * 
	 * @param {Object}
	 *            point
	 */
	setReferencePoint : function(point) {
		// Set the referencepoint
		if (this.referencePoint !== point
				&& (!this.referencePoint || !point
						|| this.referencePoint.x !== point.x || this.referencePoint.y !== point.y)) {

			this.referencePoint = point;
			this._changed();
		}

		// Update directly, because the referencepoint has no influence of the
		// bounds
		// this.refresh();
	},

	/**
	 * Get the absolute referencepoint
	 */
	getAbsoluteReferencePoint : function() {
		if (!this.referencePoint || !this._dockedShape) {
			return undefined;
		} else {
			var absUL = this._dockedShape.absoluteXY();
			return {
				x : this.referencePoint.x + absUL.x,
				y : this.referencePoint.y + absUL.y
			}
		}
	},

	/**
	 * Set the docked Shape from the docker
	 * 
	 * @param {Object}
	 *            shape
	 */
	setDockedShape : function(shape) {

		// If there is an old docked Shape
		if (this._dockedShape) {
			this._dockedShape.bounds.unregisterCallback(this._updateCallback)

			// Delete the Shapes from the incoming and outgoing array
			// If this Docker the incoming of the Shape
			if (this === this.parent.dockers.first()) {

				this.parent.incoming = this.parent.incoming
						.without(this._dockedShape);
				this._dockedShape.outgoing = this._dockedShape.outgoing
						.without(this.parent);

				// If this Docker the outgoing of the Shape
			} else if (this === this.parent.dockers.last()) {

				this.parent.outgoing = this.parent.outgoing
						.without(this._dockedShape);
				this._dockedShape.incoming = this._dockedShape.incoming
						.without(this.parent);

			}

		}

		// Set the new Shape
		this._dockedShape = shape;
		this._dockedShapeBounds = undefined;
		var referencePoint = undefined;

		// If there is an Shape, register the updateCallback if there are
		// changes in the shape bounds
		if (this._dockedShape) {

			// Add the Shapes to the incoming and outgoing array
			// If this Docker the incoming of the Shape
			if (this === this.parent.dockers.first()) {

				this.parent.incoming.push(shape);
				shape.outgoing.push(this.parent);

				// If this Docker the outgoing of the Shape
			} else if (this === this.parent.dockers.last()) {

				this.parent.outgoing.push(shape);
				shape.incoming.push(this.parent);

			}

			// Get the bounds and set the new referencepoint
			var bounds = this.bounds;
			var absUL = shape.absoluteXY();

			/*
			 * if(shape.parent){ var b = shape.parent.bounds.upperLeft();
			 * absUL.x -= b.x; absUL.y -= b.y; }
			 */

			referencePoint = {
				x : bounds.center().x - absUL.x,
				y : bounds.center().y - absUL.y
			}

			this._dockedShapeBounds = this._dockedShape.bounds.clone();

			this._dockedShape.bounds.registerCallback(this._updateCallback);

			// Set the color of the docker as docked
			this.setDockerColor(ORYX.CONFIG.DOCKER_DOCKED_COLOR);
		} else {
			// Set the color of the docker as undocked
			this.setDockerColor(ORYX.CONFIG.DOCKER_UNDOCKED_COLOR);
		}

		// Set the referencepoint
		this.setReferencePoint(referencePoint);
		this._changed();
		// this.update();
	},

	/**
	 * Get the docked Shape
	 */
	getDockedShape : function() {
		return this._dockedShape;
	},

	/**
	 * Returns TRUE if the docker has a docked shape
	 */
	isDocked : function() {
		return !!this._dockedShape;
	},

	/**
	 * Set the Color of the Docker
	 * 
	 * @param {Object}
	 *            color
	 */
	setDockerColor : function(color) {
		this._dockerNode.lastChild.setAttributeNS(null, "fill", color);
	},

	preventHiding : function(prevent) {
		this._preventHiding = Math.max(0, (this._preventHiding || 0)
						+ (prevent ? 1 : -1));
	},

	/**
	 * Hides this UIObject and all its children.
	 */
	hide : function() {
		if (this._preventHiding) {
			return false;
		}

		// Hide docker and reference point
		this.node.setAttributeNS(null, 'visibility', 'hidden');
		this._referencePointNode.setAttributeNS(null, 'visibility', 'hidden');

		this.children.each(function(uiObj) {
					uiObj.hide();
				});
	},

	/**
	 * Enables visibility of this UIObject and all its children.
	 */
	show : function() {
		// Show docker
		this.node.setAttributeNS(null, 'visibility', 'visible');

		// Hide reference point if the connected shape is an edge
		if (this.getDockedShape() instanceof ORYX.Core.Edge) {
			this._referencePointNode.setAttributeNS(null, 'visibility',
					'hidden');
		} else {
			this._referencePointNode.setAttributeNS(null, 'visibility',
					'visible');
		}

		this.children.each(function(uiObj) {
					uiObj.show();
				});
	},

	toString : function() {
		return "Docker " + this.id
	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}
if (!ORYX.Core.Controls) {
	ORYX.Core.Controls = {};
}

/**
 * @classDescription Represents a magnet that is part of another shape and can
 *                   be attached to dockers. Magnets are used for linking edge
 *                   objects to other Shape objects.
 * @extends {Control}
 */
ORYX.Core.Controls.Magnet = ORYX.Core.Controls.Control.extend({

			/**
			 * Constructor
			 */
			construct : function() {
				arguments.callee.$.construct.apply(this, arguments);

				// this.anchors = [];
				this.anchorLeft;
				this.anchorRight;
				this.anchorTop;
				this.anchorBottom;

				this.bounds.set(0, 0, 16, 16);

				// graft magnet's root node into owner's control group.
				this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
						null, ['g', {
									"pointer-events" : "all"
								}, ['circle', {
											cx : "8",
											cy : "8",
											r : "4",
											stroke : "none",
											fill : "red",
											"fill-opacity" : "0.3"
										}],]);

				this.hide();
			},

			update : function() {
				arguments.callee.$.update.apply(this, arguments);

				// this.isChanged = true;
			},

			_update : function() {
				arguments.callee.$.update.apply(this, arguments);

				// this.isChanged = true;
			},

			refresh : function() {
				arguments.callee.$.refresh.apply(this, arguments);

				var p = this.bounds.upperLeft();
				/*
				 * if(this.parent) { var parentPos =
				 * this.parent.bounds.upperLeft(); p.x += parentPos.x; p.y +=
				 * parentPos.y; }
				 */

				this.node.setAttributeNS(null, 'transform', 'translate(' + p.x
								+ ', ' + p.y + ')');
			},

			show : function() {
				// this.refresh();
				arguments.callee.$.show.apply(this, arguments);
			},

			toString : function() {
				return "Magnet " + this.id;
			}
		});
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}

/**
 * @classDescription Abstract base class for all Nodes.
 * @extends ORYX.Core.Shape
 */
ORYX.Core.Node = {

	/**
	 * Constructor
	 * 
	 * @param options
	 *            {Object} A container for arguments.
	 * @param stencil
	 *            {Stencil}
	 */
	construct : function(options, stencil, facade) {
		arguments.callee.$.construct.apply(this, arguments);

		this.isSelectable = true;
		this.isMovable = true;
		this._dockerUpdated = false;
		this.facade = facade;

		this._oldBounds = new ORYX.Core.Bounds(); // init bounds with
													// undefined values
		this._svgShapes = []; // array of all SVGShape objects of
		// SVG representation

		// TODO vielleicht in shape verschieben?
		this.minimumSize = undefined; // {width:..., height:...}
		this.maximumSize = undefined;

		// TODO vielleicht in shape oder uiobject verschieben?
		// vielleicht sogar isResizable ersetzen?
		this.isHorizontallyResizable = false;
		this.isVerticallyResizable = false;

		this.dataId = undefined;

		this._init(this._stencil.view());
		this.forcedHeight = -1;
	},

	/**
	 * This method checks whether the shape is resized correctly and calls the
	 * super class update method.
	 */
	_update : function() {

		this.dockers.invoke("update");
		if (this.isChanged) {

			var bounds = this.bounds;
			var oldBounds = this._oldBounds;

			if (this.isResized) {

				var widthDelta = bounds.width() / oldBounds.width();
				var heightDelta = bounds.height() / oldBounds.height();

				// iterate over all relevant svg elements and resize them
				this._svgShapes.each(function(svgShape) {
							// adjust width
							if (svgShape.isHorizontallyResizable) {
								svgShape.width = svgShape.oldWidth * widthDelta;
							}
							// adjust height
							if (svgShape.isVerticallyResizable) {
								svgShape.height = svgShape.oldHeight
										* heightDelta;
							}

							// check, if anchors are set
							var anchorOffset;
							var leftIncluded = svgShape.anchorLeft;
							var rightIncluded = svgShape.anchorRight;

							if (rightIncluded) {
								anchorOffset = oldBounds.width()
										- (svgShape.oldX + svgShape.oldWidth);
								if (leftIncluded) {
									svgShape.width = bounds.width()
											- svgShape.x - anchorOffset;
								} else {
									svgShape.x = bounds.width()
											- (anchorOffset + svgShape.width);
								}
							} else if (!leftIncluded) {
								svgShape.x = widthDelta * svgShape.oldX;
								if (!svgShape.isHorizontallyResizable) {
									svgShape.x = svgShape.x + svgShape.width
											* widthDelta / 2 - svgShape.width
											/ 2;
								}
							}

							var topIncluded = svgShape.anchorTop;
							var bottomIncluded = svgShape.anchorBottom;

							if (bottomIncluded) {
								anchorOffset = oldBounds.height()
										- (svgShape.oldY + svgShape.oldHeight);
								if (topIncluded) {
									svgShape.height = bounds.height()
											- svgShape.y - anchorOffset;
								} else {
									// Hack for choreography task layouting
									if (!svgShape._isYLocked) {
										svgShape.y = bounds.height()
												- (anchorOffset + svgShape.height);
									}
								}
							} else if (!topIncluded) {
								svgShape.y = heightDelta * svgShape.oldY;
								if (!svgShape.isVerticallyResizable) {
									svgShape.y = svgShape.y + svgShape.height
											* heightDelta / 2 - svgShape.height
											/ 2;
								}
							}
						});

				// check, if the current bounds is unallowed horizontally or
				// vertically resized
				var p = {
					x : 0,
					y : 0
				};
				if (!this.isHorizontallyResizable
						&& bounds.width() !== oldBounds.width()) {
					p.x = oldBounds.width() - bounds.width();
				}
				if (!this.isVerticallyResizable
						&& bounds.height() !== oldBounds.height()) {
					p.y = oldBounds.height() - bounds.height();
				}
				if (p.x !== 0 || p.y !== 0) {
					bounds.extend(p);
				}

				// check, if the current bounds are between maximum and minimum
				// bounds
				p = {
					x : 0,
					y : 0
				};
				var widthDifference, heightDifference;
				if (this.minimumSize) {

					ORYX.Log.debug("Shape (%0)'s min size: (%1x%2)", this,
							this.minimumSize.width, this.minimumSize.height);
					widthDifference = this.minimumSize.width - bounds.width();
					if (widthDifference > 0) {
						p.x += widthDifference;
					}
					heightDifference = this.minimumSize.height
							- bounds.height();
					if (heightDifference > 0) {
						p.y += heightDifference;
					}
				}
				if (this.maximumSize) {

					ORYX.Log.debug("Shape (%0)'s max size: (%1x%2)", this,
							this.maximumSize.width, this.maximumSize.height);
					widthDifference = bounds.width() - this.maximumSize.width;
					if (widthDifference > 0) {
						p.x -= widthDifference;
					}
					heightDifference = bounds.height()
							- this.maximumSize.height;
					if (heightDifference > 0) {
						p.y -= heightDifference;
					}
				}
				if (p.x !== 0 || p.y !== 0) {
					bounds.extend(p);
				}

				// update magnets

				var widthDelta = bounds.width() / oldBounds.width();
				var heightDelta = bounds.height() / oldBounds.height();

				var leftIncluded, rightIncluded, topIncluded, bottomIncluded, center, newX, newY;

				this.magnets.each(function(magnet) {
							leftIncluded = magnet.anchorLeft;
							rightIncluded = magnet.anchorRight;
							topIncluded = magnet.anchorTop;
							bottomIncluded = magnet.anchorBottom;

							center = magnet.bounds.center();

							if (leftIncluded) {
								newX = center.x;
							} else if (rightIncluded) {
								newX = bounds.width()
										- (oldBounds.width() - center.x)
							} else {
								newX = center.x * widthDelta;
							}

							if (topIncluded) {
								newY = center.y;
							} else if (bottomIncluded) {
								newY = bounds.height()
										- (oldBounds.height() - center.y);
							} else {
								newY = center.y * heightDelta;
							}

							if (center.x !== newX || center.y !== newY) {
								magnet.bounds.centerMoveTo(newX, newY);
							}
						});

				// set new position of labels
				this.getLabels().each(function(label) {
					// Set the position dependings on it anchor
					if (!label.isAnchorLeft()) {
						if (label.isAnchorRight()) {
							label.setX(bounds.width()
									- (oldBounds.width() - label.oldX))
						} else {
							label.setX((label.position
									? label.position.x
									: label.x)
									* widthDelta);
						}
					}
					if (!label.isAnchorTop()) {
						if (label.isAnchorBottom()) {
							label.setY(bounds.height()
									- (oldBounds.height() - label.oldY));
						} else {
							label.setY((label.position
									? label.position.y
									: label.y)
									* heightDelta);
						}
					}

					// If there is an position,
					// set the origin position as well
					if (label.position) {
						if (!label.isOriginAnchorLeft()) {
							if (label.isOriginAnchorRight()) {
								label.setOriginX(bounds.width()
										- (oldBounds.width() - label.oldX))
							} else {
								label.setOriginX(label.x * widthDelta);
							}
						}
						if (!label.isOriginAnchorTop()) {
							if (label.isOriginAnchorBottom()) {
								label.setOriginY(bounds.height()
										- (oldBounds.height() - label.oldY));
							} else {
								label.setOriginY(label.y * heightDelta);
							}
						}
					}
				});

				// update docker
				var docker = this.dockers[0];
				if (docker) {
					docker.bounds
							.unregisterCallback(this._dockerChangedCallback);
					if (!this._dockerUpdated) {
						docker.bounds.centerMoveTo(this.bounds.center());
						this._dockerUpdated = false;
					}

					docker.update();
					docker.bounds.registerCallback(this._dockerChangedCallback);
				}
				this.isResized = false;
			}

			this.refresh();

			this.isChanged = false;

			this._oldBounds = this.bounds.clone();
		}

		this.children.each(function(value) {
					if (!(value instanceof ORYX.Core.Controls.Docker)) {
						value._update();
					}
				});

		if (this.dockers.length > 0 && !this.dockers.first().getDockedShape()) {
			this.dockers.each(function(docker) {
						docker.bounds.centerMoveTo(this.bounds.center())
					}.bind(this))
		}

		/*
		 * this.incoming.each((function(edge) { if(!(this.dockers[0] &&
		 * this.dockers[0].getDockedShape() instanceof ORYX.Core.Node))
		 * edge._update(true); }).bind(this));
		 * 
		 * this.outgoing.each((function(edge) { if(!(this.dockers[0] &&
		 * this.dockers[0].getDockedShape() instanceof ORYX.Core.Node))
		 * edge._update(true); }).bind(this));
		 */
	},

	/**
	 * This method repositions and resizes the SVG representation of the shape.
	 */
	refresh : function() {
		arguments.callee.$.refresh.apply(this, arguments);

		/** Movement */
		var x = this.bounds.upperLeft().x;
		var y = this.bounds.upperLeft().y;

		// Move owner element
		this.node.firstChild.setAttributeNS(null, "transform", "translate(" + x
						+ ", " + y + ")");
		// Move magnets
		this.node.childNodes[1].childNodes[1].setAttributeNS(null, "transform",
				"translate(" + x + ", " + y + ")");

		/** Resize */

		// iterate over all relevant svg elements and update them
		this._svgShapes.each(function(svgShape) {
					svgShape.update();
				});
	},

	_dockerChanged : function() {
		var docker = this.dockers[0];

		// set the bounds of the the association
		this.bounds.centerMoveTo(docker.bounds.center());

		this._dockerUpdated = true;
		// this._update(true);
	},

	/**
	 * This method traverses a tree of SVGElements and returns all SVGShape
	 * objects. For each basic shape or path element a SVGShape object is
	 * initialized.
	 * 
	 * @param svgNode
	 *            {SVGElement}
	 * @return {Array} Array of SVGShape objects
	 */
	_initSVGShapes : function(svgNode) {
		var svgShapes = [];
		try {
			var svgShape = new ORYX.Core.SVG.SVGShape(svgNode);
			svgShapes.push(svgShape);
		} catch (e) {
			// do nothing
		}

		if (svgNode.hasChildNodes()) {
			for (var i = 0; i < svgNode.childNodes.length; i++) {
				svgShapes = svgShapes.concat(this
						._initSVGShapes(svgNode.childNodes[i]));
			}
		}

		return svgShapes;
	},

	/**
	 * Calculate if the point is inside the Shape
	 * 
	 * @param {PointX}
	 * @param {PointY}
	 * @param {absoluteBounds}
	 *            optional: for performance
	 */
	isPointIncluded : function(pointX, pointY, absoluteBounds) {
		// If there is an arguments with the absoluteBounds
		var absBounds = absoluteBounds
				&& absoluteBounds instanceof ORYX.Core.Bounds
				? absoluteBounds
				: this.absoluteBounds();

		if (!absBounds.isIncluded(pointX, pointY)) {
			return false;
		} else {

		}

		// point = Object.clone(point);
		var ul = absBounds.upperLeft();
		var x = pointX - ul.x;
		var y = pointY - ul.y;

		var i = 0;
		do {
			var isPointIncluded = this._svgShapes[i++].isPointIncluded(x, y);
		} while (!isPointIncluded && i < this._svgShapes.length)

		return isPointIncluded;

		/*
		 * return this._svgShapes.any(function(svgShape){ return
		 * svgShape.isPointIncluded(point); });
		 */
	},

	/**
	 * Calculate if the point is over an special offset area
	 * 
	 * @param {Point}
	 */
	isPointOverOffset : function(pointX, pointY) {
		var isOverEl = arguments.callee.$.isPointOverOffset.apply(this,
				arguments);

		if (isOverEl) {

			// If there is an arguments with the absoluteBounds
			var absBounds = this.absoluteBounds();
			absBounds.widen(-ORYX.CONFIG.BORDER_OFFSET);

			if (!absBounds.isIncluded(pointX, pointY)) {
				return true;
			}
		}

		return false;

	},

	serialize : function() {
		var result = arguments.callee.$.serialize.apply(this);

		// Add the docker's bounds
		// nodes only have at most one docker!
		this.dockers.each((function(docker) {
					if (docker.getDockedShape()) {
						var center = docker.referencePoint;
						center = center ? center : docker.bounds.center();
						result.push({
									name : 'docker',
									prefix : 'oryx',
									value : $H(center).values().join(','),
									type : 'literal'
								});
					}
				}).bind(this));

		// Get the spezific serialized object from the stencil
		try {
			// result = this.getStencil().serialize(this, result);

			var serializeEvent = this.getStencil().serialize();

			/*
			 * call serialize callback by reference, result should be found in
			 * serializeEvent.result
			 */
			if (serializeEvent.type) {
				serializeEvent.shape = this;
				serializeEvent.data = result;
				serializeEvent.result = undefined;
				serializeEvent.forceExecution = true;

				this._delegateEvent(serializeEvent);

				if (serializeEvent.result) {
					result = serializeEvent.result;
				}
			}
		} catch (e) {
		}
		return result;
	},

	deserialize : function(data) {
		arguments.callee.$.deserialize.apply(this, arguments);

		try {
			// data = this.getStencil().deserialize(this, data);

			var deserializeEvent = this.getStencil().deserialize();

			/*
			 * call serialize callback by reference, result should be found in
			 * serializeEventInfo.result
			 */
			if (deserializeEvent.type) {
				deserializeEvent.shape = this;
				deserializeEvent.data = data;
				deserializeEvent.result = undefined;
				deserializeEvent.forceExecution = true;

				this._delegateEvent(deserializeEvent);
				if (deserializeEvent.result) {
					data = deserializeEvent.result;
				}
			}
		} catch (e) {
		}

		// Set the outgoing shapes
		var outgoing = data.findAll(function(ser) {
					return (ser.prefix + "-" + ser.name) == 'raziel-outgoing'
				});
		outgoing.each((function(obj) {
					// TODO: Look at Canvas
					if (!this.parent) {
						return
					};

					// Set outgoing Shape
					var next = this.getCanvas()
							.getChildShapeByResourceId(obj.value);

					if (next) {
						if (next instanceof ORYX.Core.Edge) {
							// Set the first docker of the next shape
							next.dockers.first().setDockedShape(this);
							next.dockers.first().setReferencePoint(next.dockers
									.first().bounds.center());
						} else if (next.dockers.length > 0) { // next is a
																// node and next
																// has a docker
							next.dockers.first().setDockedShape(this);
							// next.dockers.first().setReferencePoint({x:
							// this.bounds.width() / 2.0, y:
							// this.bounds.height() / 2.0});
						}
					}

				}).bind(this));

		if (this.dockers.length === 1) {
			var dockerPos;
			dockerPos = data.find(function(entry) {
						return (entry.prefix + "-" + entry.name === "oryx-dockers");
					});

			if (dockerPos) {
				var points = dockerPos.value.replace(/,/g, " ").split(" ")
						.without("").without("#");
				if (points.length === 2 && this.dockers[0].getDockedShape()) {
					this.dockers[0].setReferencePoint({
								x : parseFloat(points[0]),
								y : parseFloat(points[1])
							});
				} else {
					this.dockers[0].bounds.centerMoveTo(parseFloat(points[0]),
							parseFloat(points[1]));
				}
			}
		}
	},

	/**
	 * This method excepts the SVGDoucment that is the SVG representation of
	 * this shape. The bounds of the shape are calculated, the SVG
	 * representation's upper left point is moved to 0,0 and it the method sets
	 * if this shape is resizable.
	 * 
	 * @param {SVGDocument}
	 *            svgDocument
	 */
	_init : function(svgDocument) {
		arguments.callee.$._init.apply(this, arguments);

		var svgNode = svgDocument.getElementsByTagName("g")[0]; // outer most g
																// node
		// set all required attributes
		var attributeTitle = svgDocument.ownerDocument.createAttribute("title");
		attributeTitle.nodeValue = this.getStencil().title();
		svgNode.setAttributeNode(attributeTitle);

		var attributeId = svgDocument.ownerDocument.createAttribute("id");
		attributeId.nodeValue = this.id;
		svgNode.setAttributeNode(attributeId);

		// 
		var stencilTargetNode = this.node.childNodes[0].childNodes[0]; // <g
																		// class=me>"
		svgNode = stencilTargetNode.appendChild(svgNode);

		// Add to the EventHandler
		this.addEventHandlers(svgNode.parentNode);

		/** set minimum and maximum size */
		var minSizeAttr = svgNode.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX,
				"minimumSize");
		if (minSizeAttr) {
			minSizeAttr = minSizeAttr.replace("/,/g", " ");
			var minSizeValues = minSizeAttr.split(" ");
			minSizeValues = minSizeValues.without("");

			if (minSizeValues.length > 1) {
				this.minimumSize = {
					width : parseFloat(minSizeValues[0]),
					height : parseFloat(minSizeValues[1])
				};
			} else {
				// set minimumSize to (1,1), so that width and height of the
				// stencil can never be (0,0)
				this.minimumSize = {
					width : 1,
					height : 1
				};
			}
		}

		var maxSizeAttr = svgNode.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX,
				"maximumSize");
		if (maxSizeAttr) {
			maxSizeAttr = maxSizeAttr.replace("/,/g", " ");
			var maxSizeValues = maxSizeAttr.split(" ");
			maxSizeValues = maxSizeValues.without("");

			if (maxSizeValues.length > 1) {
				this.maximumSize = {
					width : parseFloat(maxSizeValues[0]),
					height : parseFloat(maxSizeValues[1])
				};
			}
		}

		if (this.minimumSize
				&& this.maximumSize
				&& (this.minimumSize.width > this.maximumSize.width || this.minimumSize.height > this.maximumSize.height)) {

			// TODO wird verschluckt!!!
			throw this + ": Minimum Size must be greater than maxiumSize.";
		}

		/** get current bounds and adjust it to upperLeft == (0,0) */
		// initialize all SVGShape objects
		this._svgShapes = this._initSVGShapes(svgNode);

		// get upperLeft and lowerRight of stencil
		var upperLeft = {
			x : undefined,
			y : undefined
		};
		var lowerRight = {
			x : undefined,
			y : undefined
		};
		var me = this;
		this._svgShapes.each(function(svgShape) {
					upperLeft.x = (upperLeft.x !== undefined) ? Math.min(
							upperLeft.x, svgShape.x) : svgShape.x;
					upperLeft.y = (upperLeft.y !== undefined) ? Math.min(
							upperLeft.y, svgShape.y) : svgShape.y;
					lowerRight.x = (lowerRight.x !== undefined)
							? Math.max(lowerRight.x, svgShape.x
											+ svgShape.width)
							: svgShape.x + svgShape.width;
					lowerRight.y = (lowerRight.y !== undefined)
							? Math.max(lowerRight.y, svgShape.y
											+ svgShape.height)
							: svgShape.y + svgShape.height;

					/** set if resizing is enabled */
					// TODO isResizable durch die beiden anderen booleans
					// ersetzen?
					if (svgShape.isHorizontallyResizable) {
						me.isHorizontallyResizable = true;
						me.isResizable = true;
					}
					if (svgShape.isVerticallyResizable) {
						me.isVerticallyResizable = true;
						me.isResizable = true;
					}
					if (svgShape.anchorTop && svgShape.anchorBottom) {
						me.isVerticallyResizable = true;
						me.isResizable = true;
					}
					if (svgShape.anchorLeft && svgShape.anchorRight) {
						me.isHorizontallyResizable = true;
						me.isResizable = true;
					}
				});

		// move all SVGShapes by -upperLeft
		this._svgShapes.each(function(svgShape) {
					svgShape.x -= upperLeft.x;
					svgShape.y -= upperLeft.y;
					svgShape.update();
				});

		// set bounds of shape
		// the offsets are also needed for positioning the magnets and the
		// docker
		var offsetX = upperLeft.x;
		var offsetY = upperLeft.y;

		lowerRight.x -= offsetX;
		lowerRight.y -= offsetY;
		upperLeft.x = 0;
		upperLeft.y = 0;

		// prevent that width or height of initial bounds is 0
		if (lowerRight.x === 0) {
			lowerRight.x = 1;
		}
		if (lowerRight.y === 0) {
			lowerRight.y = 1;
		}

		this._oldBounds.set(upperLeft, lowerRight);
		this.bounds.set(upperLeft, lowerRight);

		/** initialize magnets */

		var magnets = svgDocument.getElementsByTagNameNS(
				ORYX.CONFIG.NAMESPACE_ORYX, "magnets");

		if (magnets && magnets.length > 0) {

			magnets = $A(magnets[0].getElementsByTagNameNS(
					ORYX.CONFIG.NAMESPACE_ORYX, "magnet"));

			var me = this;
			magnets.each(function(magnetElem) {
						var magnet = new ORYX.Core.Controls.Magnet({
									eventHandlerCallback : me.eventHandlerCallback
								});
						var cx = parseFloat(magnetElem.getAttributeNS(
								ORYX.CONFIG.NAMESPACE_ORYX, "cx"));
						var cy = parseFloat(magnetElem.getAttributeNS(
								ORYX.CONFIG.NAMESPACE_ORYX, "cy"));
						magnet.bounds.centerMoveTo({
									x : cx - offsetX,
									y : cy - offsetY
								});

						// get anchors
						var anchors = magnetElem.getAttributeNS(
								ORYX.CONFIG.NAMESPACE_ORYX, "anchors");
						if (anchors) {
							anchors = anchors.replace("/,/g", " ");
							anchors = anchors.split(" ").without("");
							for (var i = 0; i < anchors.length; i++) {
								switch (anchors[i].toLowerCase()) {
									case "left" :
										magnet.anchorLeft = true;
										break;
									case "right" :
										magnet.anchorRight = true;
										break;
									case "top" :
										magnet.anchorTop = true;
										break;
									case "bottom" :
										magnet.anchorBottom = true;
										break;
								}
							}
						}

						me.add(magnet);

						// check, if magnet is default magnet
						if (!this._defaultMagnet) {
							var defaultAttr = magnetElem.getAttributeNS(
									ORYX.CONFIG.NAMESPACE_ORYX, "default");
							if (defaultAttr
									&& defaultAttr.toLowerCase() === "yes") {
								me._defaultMagnet = magnet;
							}
						}
					});
		} else {
			// Add a Magnet in the Center of Shape
			var magnet = new ORYX.Core.Controls.Magnet();
			magnet.bounds.centerMoveTo(this.bounds.width() / 2, this.bounds
							.height()
							/ 2);
			this.add(magnet);
		}

		/** initialize docker */
		var dockerElem = svgDocument.getElementsByTagNameNS(
				ORYX.CONFIG.NAMESPACE_ORYX, "docker");

		if (dockerElem && dockerElem.length > 0) {
			dockerElem = dockerElem[0];
			var docker = this.createDocker();
			var cx = parseFloat(dockerElem.getAttributeNS(
					ORYX.CONFIG.NAMESPACE_ORYX, "cx"));
			var cy = parseFloat(dockerElem.getAttributeNS(
					ORYX.CONFIG.NAMESPACE_ORYX, "cy"));
			docker.bounds.centerMoveTo({
						x : cx - offsetX,
						y : cy - offsetY
					});

			// get anchors
			var anchors = dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX,
					"anchors");
			if (anchors) {
				anchors = anchors.replace("/,/g", " ");
				anchors = anchors.split(" ").without("");

				for (var i = 0; i < anchors.length; i++) {
					switch (anchors[i].toLowerCase()) {
						case "left" :
							docker.anchorLeft = true;
							break;
						case "right" :
							docker.anchorRight = true;
							break;
						case "top" :
							docker.anchorTop = true;
							break;
						case "bottom" :
							docker.anchorBottom = true;
							break;
					}
				}
			}
		}

		/** initialize labels */
		var textElems = svgNode.getElementsByTagNameNS(
				ORYX.CONFIG.NAMESPACE_SVG, 'text');
		$A(textElems).each((function(textElem) {
			var label = new ORYX.Core.SVG.Label({
						textElement : textElem,
						shapeId : this.id
					});
			label.x -= offsetX;
			label.y -= offsetY;
			this._labels[label.id] = label;

			label.registerOnChange(this.layout.bind(this));

			// Only apply fitting on form-components
			if (this._stencil.id().indexOf(ORYX.CONFIG.FORM_ELEMENT_ID_PREFIX) == 0) {
				label.registerOnChange(this.fitToLabels.bind(this));
			}

		}).bind(this));
	},

	fitToLabels : function() {
		var y = 0;

		this.getLabels().each(function(label) {
					var lr = label.getY() + label.getHeight();
					if (lr > y) {
						y = lr;
					}
				});

		var bounds = this.bounds;
		var boundsChanged = false;

		if (this.minimumSize) {
			// Check if y-value exceeds the min-value. If not, stick to this
			// value.
			var minHeight = this.minimumSize.height;
			if (y < minHeight && bounds.height() > minHeight
					&& minHeight > this.forcedHeight) {
				bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds
								.lowerRight().x, bounds.upperLeft().y
								+ minHeight);
				boundsChanged = true;
			} else if (y > minHeight && bounds.height() != y
					&& y > this.forcedHeight) {
				bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds
								.lowerRight().x, bounds.upperLeft().y + y);
				boundsChanged = true;
			} else if (bounds.height() > this.forcedHeight
					&& this.forcedHeight > 0) {
				bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds
								.lowerRight().x, bounds.upperLeft().y
								+ this.forcedHeight);
				boundsChanged = true;
			}
		}

		if (boundsChanged) {
			// Force facade to re-layout since bounds are changed AFTER layout
			// has been performed
			if (this.facade.getCanvas() != null) {
				this.facade.getCanvas().update();
			}

			// Re-select if needed to force the select
			if (this.facade.getSelection().member(this)) {
				var selectedNow = this.facade.getSelection();
				this.facade.setSelection([]);
				this.facade.setSelection(selectedNow);
			}
		}
	},

	/**
	 * Override the Method, that a docker is not shown
	 * 
	 */
	createDocker : function() {
		var docker = new ORYX.Core.Controls.Docker({
					eventHandlerCallback : this.eventHandlerCallback
				});
		docker.bounds.registerCallback(this._dockerChangedCallback);

		this.dockers.push(docker);
		docker.parent = this;
		docker.bounds.registerCallback(this._changedCallback);

		return docker
	},

	toString : function() {
		return this._stencil.title() + " " + this.id
	}
};
ORYX.Core.Node = ORYX.Core.Shape.extend(ORYX.Core.Node);
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

NAMESPACE_SVG = "http://www.w3.org/2000/svg";
NAMESPACE_ORYX = "http://www.b3mn.org/oryx";

/**
 * Init namespaces
 */
if (!ORYX) {
	var ORYX = {};
}
if (!ORYX.Core) {
	ORYX.Core = {};
}

/**
 * @classDescription Abstract base class for all connections.
 * @extends {ORYX.Core.Shape}
 * @param options
 *            {Object}
 * 
 * TODO da die verschiebung der Edge nicht ueber eine translation gemacht wird,
 * die sich auch auf alle kind UIObjects auswirkt, muessen die kinder hier beim
 * verschieben speziell betrachtet werden. Das sollte ueberarbeitet werden.
 * 
 */
ORYX.Core.Edge = {
	/**
	 * Constructor
	 * 
	 * @param {Object}
	 *            options
	 * @param {Stencil}
	 *            stencil
	 */
	construct : function(options, stencil, facade) {
		arguments.callee.$.construct.apply(this, arguments);

		this.isMovable = true;
		this.isSelectable = true;

		this._dockerUpdated = false;

		this._markers = new Hash(); // a hash map of SVGMarker objects where
									// keys are the marker ids
		this._paths = [];
		this._interactionPaths = [];
		this._dockersByPath = new Hash();
		this._markersByPath = new Hash();

		/*
		 * Data structures to store positioning information of attached child
		 * nodes
		 */
		this.attachedNodePositionData = new Hash();

		// TODO was muss hier initial erzeugt werden?
		var stencilNode = this.node.childNodes[0].childNodes[0];
		stencilNode = ORYX.Editor.graft("http://www.w3.org/2000/svg",
				stencilNode, ['g', {
							"pointer-events" : "painted"
						}]);

		// Add to the EventHandler
		this.addEventHandlers(stencilNode.parentNode);

		this._oldBounds = this.bounds.clone();

		// load stencil
		this._init(this._stencil.view());

		if (stencil instanceof Array) {
			this.deserialize(stencil);
		}

	},

	_update : function(force) {
		if (this._dockerUpdated || this.isChanged || force) {

			this.dockers.invoke("update");

			if (false && (this.bounds.width() === 0 || this.bounds.height() === 0)) {
				var width = this.bounds.width();
				var height = this.bounds.height();
				this.bounds.extend({
							x : width === 0 ? 2 : 0,
							y : height === 0 ? 2 : 0
						});
				this.bounds.moveBy({
							x : width === 0 ? -1 : 0,
							y : height === 0 ? -1 : 0
						});

			}

			// TODO: Bounds muss abhaengig des Eltern-Shapes gesetzt werden
			var upL = this.bounds.upperLeft();
			var oldUpL = this._oldBounds.upperLeft();
			var oldWidth = this._oldBounds.width() === 0
					? this.bounds.width()
					: this._oldBounds.width();
			var oldHeight = this._oldBounds.height() === 0 ? this.bounds
					.height() : this._oldBounds.height();
			var diffX = upL.x - oldUpL.x;
			var diffY = upL.y - oldUpL.y;
			var diffWidth = (this.bounds.width() / oldWidth) || 1;
			var diffHeight = (this.bounds.height() / oldHeight) || 1;

			this.dockers.each((function(docker) {
						// Unregister on BoundsChangedCallback
						docker.bounds
								.unregisterCallback(this._dockerChangedCallback);

						// If there is any changes at the edge and is there is
						// not an DockersUpdate
						// set the new bounds to the docker
						if (!this._dockerUpdated) {
							docker.bounds.moveBy(diffX, diffY);

							if (diffWidth !== 1 || diffHeight !== 1) {
								var relX = docker.bounds.upperLeft().x - upL.x;
								var relY = docker.bounds.upperLeft().y - upL.y;

								docker.bounds.moveTo(upL.x + relX * diffWidth,
										upL.y + relY * diffHeight);
							}
						}
						// Do Docker update and register on DockersBoundChange
						docker.update();
						docker.bounds
								.registerCallback(this._dockerChangedCallback);

					}).bind(this));

			if (this._dockerUpdated) {
				var a = this.dockers.first().bounds.center();
				var b = this.dockers.first().bounds.center();

				this.dockers.each((function(docker) {
							var center = docker.bounds.center();
							a.x = Math.min(a.x, center.x);
							a.y = Math.min(a.y, center.y);
							b.x = Math.max(b.x, center.x);
							b.y = Math.max(b.y, center.y);
						}).bind(this));

				// set the bounds of the the association
				this.bounds.set(Object.clone(a), Object.clone(b));
			}

			upL = this.bounds.upperLeft();
			oldUpL = this._oldBounds.upperLeft();
			diffWidth = (this.bounds.width() / (oldWidth || this.bounds.width()));
			diffHeight = (this.bounds.height() / (oldHeight || this.bounds
					.height()));
			diffX = upL.x - oldUpL.x;
			diffY = upL.y - oldUpL.y;

			// reposition labels
			this.getLabels().each(function(label) {

				if (label.getReferencePoint()) {
					var ref = label.getReferencePoint();
					var from = ref.segment.from, to = ref.segment.to;
					if (!from || !from.parent || !to || !to.parent) {
						return;
					}

					var fromPosition = from.bounds.center(), toPosition = to.bounds
							.center();

					if (fromPosition.x === ref.segment.fromPosition.x
							&& fromPosition.y === ref.segment.fromPosition.y
							&& toPosition.x === ref.segment.toPosition.x
							&& toPosition.y === ref.segment.toPosition.y
							&& !ref.dirty) {
						return;
					}

					if (!this.parent.initializingShapes) {
						var oldDistance = ORYX.Core.Math
								.getDistanceBetweenTwoPoints(
										ref.segment.fromPosition,
										ref.segment.toPosition,
										ref.intersection);
						var newIntersection = ORYX.Core.Math
								.getPointBetweenTwoPoints(fromPosition,
										toPosition, isNaN(oldDistance)
												? 0.5
												: oldDistance);

						/**
						 * Set position
						 */
						// Get the orthogonal identity vector of the current
						// segment
						var oiv = ORYX.Core.Math.getOrthogonalIdentityVector(
								fromPosition, toPosition);
						var isHor = Math.abs(oiv.y) === 1, isVer = Math
								.abs(oiv.x) === 1;
						oiv.x *= ref.distance;
						oiv.y *= ref.distance; // vector * distance
						oiv.x += newIntersection.x;
						oiv.y += newIntersection.y; // vector + the intersection
													// point
						var mx = isHor
								&& ref.orientation
								&& (ref.iorientation || ref.orientation)
										.endsWith("r") ? -label.getWidth() : 0;
						var my = isVer
								&& ref.orientation
								&& (ref.iorientation || ref.orientation)
										.startsWith("l") ? -label.getHeight()
								+ 2 : 0;
						label.setX(oiv.x + mx);
						label.setY(oiv.y + my);

						// Update the reference point
						this.updateReferencePointOfLabel(label,
								newIntersection, from, to);
					} else {
						var oiv = ORYX.Core.Math.getOrthogonalIdentityVector(
								fromPosition, toPosition);
						oiv.x *= ref.distance;
						oiv.y *= ref.distance; // vector * distance
						oiv.x += ref.intersection.x;
						oiv.y += ref.intersection.y; // vector + the
														// intersection point
						label.setX(oiv.x);
						label.setY(oiv.y);
						ref.segment.fromPosition = fromPosition;
						ref.segment.toPosition = toPosition;
					}

					return;
				}

				// Update label position if no reference point is set
				if (label.position && !this.parent.initializingShapes) {
					var x = label.position.x + (diffX * (diffWidth || 1));
					if (x > this.bounds.lowerRight().x) {
						x += this.bounds.width()
								- (this.bounds.width() / (diffWidth || 1));
					}

					var y = label.position.y + (diffY * (diffHeight || 1));
					if (y > this.bounds.lowerRight().y) {
						y += this.bounds.height()
								- (this.bounds.height() / (diffHeight || 1));
					}
					label.setX(x);
					label.setY(y);
					return;
				}

				switch (label.getEdgePosition()) {
					case "starttop" :
						var angle = this._getAngle(this.dockers[0],
								this.dockers[1]);
						var pos = this.dockers.first().bounds.center();

						if (angle <= 90 || angle > 270) {
							label.horizontalAlign("left");
							label.verticalAlign("bottom");
							label.x = pos.x + label.getOffsetTop();
							label.y = pos.y - label.getOffsetTop();
							label.rotate(360 - angle, pos);
						} else {
							label.horizontalAlign("right");
							label.verticalAlign("bottom");
							label.x = pos.x - label.getOffsetTop();
							label.y = pos.y - label.getOffsetTop();
							label.rotate(180 - angle, pos);
						}

						break;

					case "startmiddle" :
						var angle = this._getAngle(this.dockers[0],
								this.dockers[1]);
						var pos = this.dockers.first().bounds.center();

						if (angle <= 90 || angle > 270) {
							label.horizontalAlign("left");
							label.verticalAlign("bottom");
							label.x = pos.x + 2;
							label.y = pos.y + 4;
							label.rotate(360 - angle, pos);
						} else {
							label.horizontalAlign("right");
							label.verticalAlign("bottom");
							label.x = pos.x + 1;
							label.y = pos.y + 4;
							label.rotate(180 - angle, pos);
						}

						break;

					case "startbottom" :
						var angle = this._getAngle(this.dockers[0],
								this.dockers[1]);
						var pos = this.dockers.first().bounds.center();

						if (angle <= 90 || angle > 270) {
							label.horizontalAlign("left");
							label.verticalAlign("top");
							label.x = pos.x + label.getOffsetBottom();
							label.y = pos.y + label.getOffsetBottom();
							label.rotate(360 - angle, pos);
						} else {
							label.horizontalAlign("right");
							label.verticalAlign("top");
							label.x = pos.x - label.getOffsetBottom();
							label.y = pos.y + label.getOffsetBottom();
							label.rotate(180 - angle, pos);
						}

						break;
					case "midtop" :
						var numOfDockers = this.dockers.length;
						if (numOfDockers % 2 == 0) {
							var angle = this._getAngle(
									this.dockers[numOfDockers / 2 - 1],
									this.dockers[numOfDockers / 2])
							var pos1 = this.dockers[numOfDockers / 2 - 1].bounds
									.center();
							var pos2 = this.dockers[numOfDockers / 2].bounds
									.center();
							var pos = {
								x : (pos1.x + pos2.x) / 2.0,
								y : (pos1.y + pos2.y) / 2.0
							};

							label.horizontalAlign("center");
							label.verticalAlign("bottom");
							label.x = pos.x;
							label.y = pos.y - label.getOffsetTop();

							if (angle <= 90 || angle > 270) {
								label.rotate(360 - angle, pos);
							} else {
								label.rotate(180 - angle, pos);
							}
						} else {
							var index = parseInt(numOfDockers / 2);
							var angle = this._getAngle(this.dockers[index],
									this.dockers[index + 1])
							var pos = this.dockers[index].bounds.center();

							if (angle <= 90 || angle > 270) {
								label.horizontalAlign("left");
								label.verticalAlign("bottom");
								label.x = pos.x + label.getOffsetTop();
								label.y = pos.y - label.getOffsetTop();
								label.rotate(360 - angle, pos);
							} else {
								label.horizontalAlign("right");
								label.verticalAlign("bottom");
								label.x = pos.x - label.getOffsetTop();
								label.y = pos.y - label.getOffsetTop();
								label.rotate(180 - angle, pos);
							}
						}

						break;
					case "midbottom" :
						var numOfDockers = this.dockers.length;
						if (numOfDockers % 2 == 0) {
							var angle = this._getAngle(
									this.dockers[numOfDockers / 2 - 1],
									this.dockers[numOfDockers / 2])
							var pos1 = this.dockers[numOfDockers / 2 - 1].bounds
									.center();
							var pos2 = this.dockers[numOfDockers / 2].bounds
									.center();
							var pos = {
								x : (pos1.x + pos2.x) / 2.0,
								y : (pos1.y + pos2.y) / 2.0
							};

							label.horizontalAlign("center");
							label.verticalAlign("top");
							label.x = pos.x;
							label.y = pos.y + label.getOffsetTop();

							if (angle <= 90 || angle > 270) {
								label.rotate(360 - angle, pos);
							} else {
								label.rotate(180 - angle, pos);
							}
						} else {
							var index = parseInt(numOfDockers / 2);
							var angle = this._getAngle(this.dockers[index],
									this.dockers[index + 1])
							var pos = this.dockers[index].bounds.center();

							if (angle <= 90 || angle > 270) {
								label.horizontalAlign("left");
								label.verticalAlign("top");
								label.x = pos.x + label.getOffsetBottom();
								label.y = pos.y + label.getOffsetBottom();
								label.rotate(360 - angle, pos);
							} else {
								label.horizontalAlign("right");
								label.verticalAlign("top");
								label.x = pos.x - label.getOffsetBottom();
								label.y = pos.y + label.getOffsetBottom();
								label.rotate(180 - angle, pos);
							}
						}

						break;
					case "endtop" :
						var length = this.dockers.length;
						var angle = this._getAngle(this.dockers[length - 2],
								this.dockers[length - 1]);
						var pos = this.dockers.last().bounds.center();

						if (angle <= 90 || angle > 270) {
							label.horizontalAlign("right");
							label.verticalAlign("bottom");
							label.x = pos.x - label.getOffsetTop();
							label.y = pos.y - label.getOffsetTop();
							label.rotate(360 - angle, pos);
						} else {
							label.horizontalAlign("left");
							label.verticalAlign("bottom");
							label.x = pos.x + label.getOffsetTop();
							label.y = pos.y - label.getOffsetTop();
							label.rotate(180 - angle, pos);
						}

						break;
					case "endbottom" :
						var length = this.dockers.length;
						var angle = this._getAngle(this.dockers[length - 2],
								this.dockers[length - 1]);
						var pos = this.dockers.last().bounds.center();

						if (angle <= 90 || angle > 270) {
							label.horizontalAlign("right");
							label.verticalAlign("top");
							label.x = pos.x - label.getOffsetBottom();
							label.y = pos.y + label.getOffsetBottom();
							label.rotate(360 - angle, pos);
						} else {
							label.horizontalAlign("left");
							label.verticalAlign("top");
							label.x = pos.x + label.getOffsetBottom();
							label.y = pos.y + label.getOffsetBottom();
							label.rotate(180 - angle, pos);
						}

						break;
				}
			}.bind(this));

			this.children.each(function(value) {
				if (value instanceof ORYX.Core.Node) {
					this.calculatePositionOfAttachedChildNode.call(this, value);
				}
			}.bind(this));

			this.refreshAttachedNodes();
			this.refresh();

			this.isChanged = false;
			this._dockerUpdated = false;

			this._oldBounds = this.bounds.clone();
		}

		// IE10 specific fix, start and end-markes get left behind when moving
		// path
		var userAgent = navigator.userAgent;
		if (navigator.appVersion.indexOf("MSIE 10") !== -1
				|| (userAgent.indexOf('Trident') !== -1 && userAgent
						.indexOf('rv:11') !== -1)) {
			this.node.parentNode.insertBefore(this.node, this.node);
		}
	},

	/**
	 * Moves a point to the upperLeft of a node's bounds.
	 * 
	 * @param {point}
	 *            point The point to move
	 * @param {ORYX.Core.Bounds}
	 *            bounds The Bounds of the related noe
	 */
	movePointToUpperLeftOfNode : function(point, bounds) {
		point.x -= bounds.width() / 2;
		point.y -= bounds.height() / 2;
	},

	/**
	 * Refreshes the visual representation of edge's attached nodes.
	 */
	refreshAttachedNodes : function() {
		this.attachedNodePositionData.values().each(function(nodeData) {
			var startPoint = nodeData.segment.docker1.bounds.center();
			var endPoint = nodeData.segment.docker2.bounds.center();
			this.relativizePoint(startPoint);
			this.relativizePoint(endPoint);

			var newNodePosition = new Object();

			/* Calculate new x-coordinate */
			newNodePosition.x = startPoint.x
					+ nodeData.relativDistanceFromDocker1
					* (endPoint.x - startPoint.x);

			/* Calculate new y-coordinate */
			newNodePosition.y = startPoint.y
					+ nodeData.relativDistanceFromDocker1
					* (endPoint.y - startPoint.y);

			/* Convert new position to the upper left of the node */
			this.movePointToUpperLeftOfNode(newNodePosition,
					nodeData.node.bounds);

			/* Move node to its new position */
			nodeData.node.bounds.moveTo(newNodePosition);
			nodeData.node._update();

		}.bind(this));
	},

	/**
	 * Calculates the position of an edge's child node. The node is placed on
	 * the path of the edge.
	 * 
	 * @param {node}
	 *            The node to calculate the new position
	 * @return {Point} The calculated upper left point of the node's shape.
	 */
	calculatePositionOfAttachedChildNode : function(node) {
		/* Initialize position */
		var position = new Object();
		position.x = 0;
		position.y = 0;

		/* Case: Node was just added */
		if (!this.attachedNodePositionData[node.getId()]) {
			this.attachedNodePositionData[node.getId()] = new Object();
			this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = 0;
			this.attachedNodePositionData[node.getId()].node = node;
			this.attachedNodePositionData[node.getId()].segment = new Object();
			this.findEdgeSegmentForNode(node);
		} else if (node.isChanged) {
			this.findEdgeSegmentForNode(node);
		}

	},

	/**
	 * Finds the appropriate edge segement for a node. The segment is choosen,
	 * which has the smallest distance to the node.
	 * 
	 * @param {ORYX.Core.Node}
	 *            node The concerning node
	 */
	findEdgeSegmentForNode : function(node) {
		var length = this.dockers.length;
		var smallestDistance = undefined;

		for (i = 1; i < length; i++) {
			var lineP1 = this.dockers[i - 1].bounds.center();
			var lineP2 = this.dockers[i].bounds.center();
			this.relativizePoint(lineP1);
			this.relativizePoint(lineP2);

			var nodeCenterPoint = node.bounds.center();
			var distance = ORYX.Core.Math.distancePointLinie(lineP1, lineP2,
					nodeCenterPoint, true);

			if ((distance || distance == 0)
					&& ((!smallestDistance && smallestDistance != 0) || distance < smallestDistance)) {

				smallestDistance = distance;

				this.attachedNodePositionData[node.getId()].segment.docker1 = this.dockers[i
						- 1];
				this.attachedNodePositionData[node.getId()].segment.docker2 = this.dockers[i];

			}

			/*
			 * Either the distance does not match the segment or the distance
			 * between docker1 and docker2 is 0
			 * 
			 * In this case choose the nearest docker as attaching point.
			 * 
			 */
			if (!distance && !smallestDistance && smallestDistance != 0) {
				(ORYX.Core.Math
						.getDistancePointToPoint(nodeCenterPoint, lineP1) < ORYX.Core.Math
						.getDistancePointToPoint(nodeCenterPoint, lineP2))
						? this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = 0
						: this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = 1;
				this.attachedNodePositionData[node.getId()].segment.docker1 = this.dockers[i
						- 1];
				this.attachedNodePositionData[node.getId()].segment.docker2 = this.dockers[i];
			}
		}

		/* Calculate position on edge segment for the node */
		if (smallestDistance || smallestDistance == 0) {
			this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = this
					.getLineParameterForPosition(
							this.attachedNodePositionData[node.getId()].segment.docker1,
							this.attachedNodePositionData[node.getId()].segment.docker2,
							node);
		}
	},

	/**
	 * 
	 * @param {ORYX.Core.Node|Object}
	 *            node or position
	 * @return {Object} An object with the following attribute:
	 *         {ORYX.Core.Docker} fromDocker, {ORYX.Core.Docker} toDocker, {X/Y}
	 *         position, {int} distance
	 */
	findSegment : function(node) {

		var length = this.dockers.length;
		var result;

		var nodeCenterPoint = node instanceof ORYX.Core.UIObject ? node.bounds
				.center() : node;

		for (i = 1; i < length; i++) {
			var lineP1 = this.dockers[i - 1].bounds.center();
			var lineP2 = this.dockers[i].bounds.center();

			var distance = ORYX.Core.Math.distancePointLinie(lineP1, lineP2,
					nodeCenterPoint, true);

			if (typeof distance == "number"
					&& (result === undefined || distance < result.distance)) {
				result = {
					distance : distance,
					fromDocker : this.dockers[i - 1],
					toDocker : this.dockers[i]
				}

			}
		}
		return result;
	},

	/**
	 * Returns the value of the scalar to determine the position of the node on
	 * line defined by docker1 and docker2.
	 * 
	 * @param {point}
	 *            docker1 The docker that defines the start of the line segment
	 * @param {point}
	 *            docker2 The docker that defines the end of the line segment
	 * @param {ORYX.Core.Node}
	 *            node The concerning node
	 * 
	 * @return {float} positionParameter The scalar value to determine the
	 *         position on the line
	 */
	getLineParameterForPosition : function(docker1, docker2, node) {
		var dockerPoint1 = docker1.bounds.center();
		var dockerPoint2 = docker2.bounds.center();
		this.relativizePoint(dockerPoint1);
		this.relativizePoint(dockerPoint2);

		var intersectionPoint = ORYX.Core.Math.getPointOfIntersectionPointLine(
				dockerPoint1, dockerPoint2, node.bounds.center(), true);
		if (!intersectionPoint) {
			return 0;
		}

		var relativeDistance = ORYX.Core.Math.getDistancePointToPoint(
				intersectionPoint, dockerPoint1)
				/ ORYX.Core.Math.getDistancePointToPoint(dockerPoint1,
						dockerPoint2);

		return relativeDistance;
	},
	/**
	 * Makes point relative to the upper left of the edge's bound.
	 * 
	 * @param {point}
	 *            point The point to relativize
	 */
	relativizePoint : function(point) {
		point.x -= this.bounds.upperLeft().x;
		point.y -= this.bounds.upperLeft().y;
	},

	/**
	 * Move the first and last docker and calls the refresh method. Attention:
	 * This does not calculates intersection point between the edge and the
	 * bounded nodes. This only works if only the nodes are moves.
	 * 
	 */
	optimizedUpdate : function() {

		var updateDocker = function(docker) {
			if (!docker._dockedShape || !docker._dockedShapeBounds)
				return;
			var off = {
				x : docker._dockedShape.bounds.a.x
						- docker._dockedShapeBounds.a.x,
				y : docker._dockedShape.bounds.a.y
						- docker._dockedShapeBounds.a.y
			};
			docker.bounds.moveBy(off);
			docker._dockedShapeBounds.moveBy(off);
		}

		updateDocker(this.dockers.first());
		updateDocker(this.dockers.last());

		this.refresh();
	},

	refresh : function() {
		// call base class refresh method
		arguments.callee.$.refresh.apply(this, arguments);

		// TODO consider points for marker mids
		var lastPoint;
		this._paths.each((function(path, index) {
					var dockers = this._dockersByPath[path.id];
					var c = undefined;
					var d = undefined;
					if (lastPoint) {
						d = "M" + lastPoint.x + " " + lastPoint.y;
					} else {
						c = dockers[0].bounds.center();
						lastPoint = c;

						d = "M" + c.x + " " + c.y;
					}

					for (var i = 1; i < dockers.length; i++) {
						// for each docker, draw a line to the center
						c = dockers[i].bounds.center();
						d = d + "L" + c.x + " " + c.y + " ";
						lastPoint = c;
					}

					path.setAttributeNS(null, "d", d);
					this._interactionPaths[index].setAttributeNS(null, "d", d);

				}).bind(this));

		/* move child shapes of an edge */
		if (this.getChildNodes().length > 0) {
			var x = this.bounds.upperLeft().x;
			var y = this.bounds.upperLeft().y;

			this.node.firstChild.childNodes[1].setAttributeNS(null,
					"transform", "translate(" + x + ", " + y + ")");
		}

	},

	/**
	 * Calculate the Border Intersection Point between two points
	 * 
	 * @param {PointA}
	 * @param {PointB}
	 */
	getIntersectionPoint : function() {

		var length = Math.floor(this.dockers.length / 2)

		return ORYX.Core.Math.midPoint(
				this.dockers[length - 1].bounds.center(),
				this.dockers[length].bounds.center())
	},

	/**
	 * Returns TRUE if the bounds is over the edge
	 * 
	 * @param {Bounds}
	 * 
	 */
	isBoundsIncluded : function(bounds) {
		var dockers = this.dockers, size = dockers.length;
		return dockers.any(function(docker, i) {
					if (i == size - 1) {
						return false;
					}
					var a = docker.bounds.center();
					var b = dockers[i + 1].bounds.center();

					return ORYX.Core.Math.isRectOverLine(a.x, a.y, b.x, b.y,
							bounds.a.x, bounds.a.y, bounds.b.x, bounds.b.y);
				});
	},

	/**
	 * Calculate if the point is inside the Shape
	 * 
	 * @param {PointX}
	 * @param {PointY}
	 */
	isPointIncluded : function(pointX, pointY) {

		var isbetweenAB = this.absoluteBounds().isIncluded(pointX, pointY,
				ORYX.CONFIG.OFFSET_EDGE_BOUNDS);

		var isPointIncluded = undefined;

		if (isbetweenAB && this.dockers.length > 0) {

			var i = 0;
			var point1, point2;

			do {

				point1 = this.dockers[i].bounds.center();
				point2 = this.dockers[++i].bounds.center();

				isPointIncluded = ORYX.Core.Math.isPointInLine(pointX, pointY,
						point1.x, point1.y, point2.x, point2.y,
						ORYX.CONFIG.OFFSET_EDGE_BOUNDS);

			} while (!isPointIncluded && i < this.dockers.length - 1)

		}

		return isPointIncluded;

	},

	/**
	 * Calculate if the point is over an special offset area
	 * 
	 * @param {Point}
	 */
	isPointOverOffset : function() {
		return false
	},

	/**
	 * Returns TRUE if the given node is a child node of the shapes node
	 * 
	 * @param {Element}
	 *            node
	 * @return {Boolean}
	 * 
	 */
	containsNode : function(node) {
		if (this._paths.include(node) || this._interactionPaths.include(node)) {
			return true;
		}
		return false;
	},

	/**
	 * Returns the angle of the line between two dockers (0 - 359.99999999)
	 */
	_getAngle : function(docker1, docker2) {
		var p1 = docker1 instanceof ORYX.Core.Controls.Docker ? docker1
				.absoluteCenterXY() : docker1;
		var p2 = docker2 instanceof ORYX.Core.Controls.Docker ? docker2
				.absoluteCenterXY() : docker2;

		return ORYX.Core.Math.getAngle(p1, p2);
	},

	alignDockers : function() {
		this._update(true);

		var firstPoint = this.dockers.first().bounds.center();
		var lastPoint = this.dockers.last().bounds.center();

		var deltaX = lastPoint.x - firstPoint.x;
		var deltaY = lastPoint.y - firstPoint.y;

		var numOfDockers = this.dockers.length - 1;

		this.dockers.each((function(docker, index) {
					var part = index / numOfDockers;
					docker.bounds
							.unregisterCallback(this._dockerChangedCallback);
					docker.bounds.moveTo(firstPoint.x + part * deltaX,
							firstPoint.y + part * deltaY);
					docker.bounds.registerCallback(this._dockerChangedCallback);
				}).bind(this));

		this._dockerChanged();
	},

	add : function(shape) {
		arguments.callee.$.add.apply(this, arguments);

		// If the new shape is a Docker which is not contained
		if (shape instanceof ORYX.Core.Controls.Docker
				&& this.dockers.include(shape)) {
			// Add it to the dockers list ordered by paths
			var pathArray = this._dockersByPath.values()[0];
			if (pathArray) {
				pathArray.splice(this.dockers.indexOf(shape), 0, shape);
			}

			/* Perform nessary adjustments on the edge's child shapes */
			this.handleChildShapesAfterAddDocker(shape);
		}
	},

	/**
	 * Performs nessary adjustments on the edge's child shapes.
	 * 
	 * @param {ORYX.Core.Controls.Docker}
	 *            docker The added docker
	 */
	handleChildShapesAfterAddDocker : function(docker) {
		/* Ensure type of Docker */
		if (!docker instanceof ORYX.Core.Controls.Docker) {
			return undefined;
		}

		var index = this.dockers.indexOf(docker);
		if (!(0 < index && index < this.dockers.length - 1)) {
			/*
			 * Exception: Expect added docker between first and last node of the
			 * edge
			 */
			return undefined;
		}

		/* Get child nodes concerning the segment of the new docker */
		var startDocker = this.dockers[index - 1];
		var endDocker = this.dockers[index + 1];

		/* Adjust the position of edge's child nodes */
		var segmentElements = this.getAttachedNodePositionDataForSegment(
				startDocker, endDocker);

		var lengthSegmentPart1 = ORYX.Core.Math.getDistancePointToPoint(
				startDocker.bounds.center(), docker.bounds.center());
		var lengthSegmentPart2 = ORYX.Core.Math.getDistancePointToPoint(
				endDocker.bounds.center(), docker.bounds.center());

		if (!(lengthSegmentPart1 + lengthSegmentPart2)) {
			return;
		}

		var relativDockerPosition = lengthSegmentPart1
				/ (lengthSegmentPart1 + lengthSegmentPart2);

		segmentElements.each(function(nodePositionData) {
			/* Assign child node to the new segment */
			if (nodePositionData.value.relativDistanceFromDocker1 < relativDockerPosition) {
				/* Case: before added Docker */
				nodePositionData.value.segment.docker2 = docker;
				nodePositionData.value.relativDistanceFromDocker1 = nodePositionData.value.relativDistanceFromDocker1
						/ relativDockerPosition;
			} else {
				/* Case: after added Docker */
				nodePositionData.value.segment.docker1 = docker;
				var newFullDistance = 1 - relativDockerPosition;
				var relativPartOfSegment = nodePositionData.value.relativDistanceFromDocker1
						- relativDockerPosition;

				nodePositionData.value.relativDistanceFromDocker1 = relativPartOfSegment
						/ newFullDistance;

			}
		})

		// Update all labels reference points
		this.getLabels().each(function(label) {

			var ref = label.getReferencePoint();
			if (!ref) {
				return;
			}
			var index = this.dockers.indexOf(docker);
			if (index >= ref.segment.fromIndex && index <= ref.segment.toIndex) {

				var segment = this.findSegment(ref.intersection);
				if (!segment) {
					// Choose whether the first of the last segment
					segment.fromDocker = ref.segment.fromIndex >= (this.dockers.length / 2)
							? this.dockers[0]
							: this.dockers[this.dockers.length - 2];
					segment.toDocker = this.dockers[this.dockers.indexOf(from)
							+ 1]; // The next one if the to docker
				}

				var fromPosition = segment.fromDocker.bounds.center(), toPosition = segment.toDocker.bounds
						.center();

				var intersection = ORYX.Core.Math
						.getPointOfIntersectionPointLine(fromPosition, // P1 -
																		// Center
																		// of
																		// the
																		// first
																		// docker
								toPosition, // P2 - Center of the second docker
								ref.intersection, // P3 - Center of the label
								true);
				// var oldDistance =
				// ORYX.Core.Math.getDistanceBetweenTwoPoints(ref.segment.fromPosition,
				// ref.segment.toPosition, ref.intersection);
				// intersection =
				// ORYX.Core.Math.getPointBetweenTwoPoints(fromPosition,
				// toPosition, isNaN(oldDistance) ? 0.5 :
				// (lengthOld*oldDistance)/lengthNew);

				// Update the reference point
				this.updateReferencePointOfLabel(label, intersection,
						segment.fromDocker, segment.toDocker, true);
			}
		}.bind(this));

		/* Update attached nodes visual representation */
		this.refreshAttachedNodes();
	},

	/**
	 * Returns elements from {@link attachedNodePositiondata} that match the
	 * segement defined by startDocker and endDocker.
	 * 
	 * @param {ORYX.Core.Controls.Docker}
	 *            startDocker The docker defining the begin of the segment.
	 * @param {ORYX.Core.Controls.Docker}
	 *            endDocker The docker defining the begin of the segment.
	 * 
	 * @return {Hash} attachedNodePositionData Child elements matching the
	 *         segment
	 */
	getAttachedNodePositionDataForSegment : function(startDocker, endDocker) {
		/* Ensure that the segment is defined correctly */
		if (!((startDocker instanceof ORYX.Core.Controls.Docker) && (endDocker instanceof ORYX.Core.Controls.Docker))) {
			return [];
		}

		/* Get elements of the segment */
		var elementsOfSegment = this.attachedNodePositionData.findAll(function(
						nodePositionData) {
					return nodePositionData.value.segment.docker1 === startDocker
							&& nodePositionData.value.segment.docker2 === endDocker;
				});

		/* Return a Hash in each case */
		if (!elementsOfSegment) {
			return [];
		}

		return elementsOfSegment;
	},

	/**
	 * Removes an edge's child shape
	 */
	remove : function(shape) {
		arguments.callee.$.remove.apply(this, arguments);

		if (this.attachedNodePositionData[shape.getId()]) {
			delete this.attachedNodePositionData[shape.getId()];
		}

		/* Adjust child shapes if neccessary */
		if (shape instanceof ORYX.Core.Controls.Docker) {
			this.handleChildShapesAfterRemoveDocker(shape);
		}
	},

	updateReferencePointOfLabel : function(label, intersection, from, to, dirty) {
		if (!label.getReferencePoint() || !label.isVisible) {
			return;
		}

		var ref = label.getReferencePoint();

		//
		if (ref.orientation && ref.orientation !== "ce") {
			var angle = this._getAngle(from, to);
			if (ref.distance >= 0) {
				if (angle == 0) {
					label.horizontalAlign("left");// ref.orientation == "lr" ?
													// "right" : "left");
					label.verticalAlign("bottom");
				} else if (angle > 0 && angle < 90) {
					label.horizontalAlign("right");
					label.verticalAlign("bottom");
				} else if (angle == 90) {
					label.horizontalAlign("right");
					label.verticalAlign("top");// ref.orientation == "lr" ?
												// "bottom" : "top");
				} else if (angle > 90 && angle < 180) {
					label.horizontalAlign("right");
					label.verticalAlign("top");
				} else if (angle == 180) {
					label.horizontalAlign("left");// ref.orientation == "ur" ?
													// "right" : "left");
					label.verticalAlign("top");
				} else if (angle > 180 && angle < 270) {
					label.horizontalAlign("left");
					label.verticalAlign("top");
				} else if (angle == 270) {
					label.horizontalAlign("left");
					label.verticalAlign("top");// ref.orientation == "ll" ?
												// "bottom" : "top");
				} else if (angle > 270 && angle <= 360) {
					label.horizontalAlign("left");
					label.verticalAlign("bottom");
				}
			} else {
				if (angle == 0) {
					label.horizontalAlign("left");// ref.orientation == "ur" ?
													// "right" : "left");
					label.verticalAlign("top");
				} else if (angle > 0 && angle < 90) {
					label.horizontalAlign("left");
					label.verticalAlign("top");
				} else if (angle == 90) {
					label.horizontalAlign("left");
					label.verticalAlign("top");// ref.orientation == "ll" ?
												// "bottom" : "top");
				} else if (angle > 90 && angle < 180) {
					label.horizontalAlign("left");
					label.verticalAlign("bottom");
				} else if (angle == 180) {
					label.horizontalAlign("left");// ref.orientation == "lr" ?
													// "right" : "left");
					label.verticalAlign("bottom");
				} else if (angle > 180 && angle < 270) {
					label.horizontalAlign("right");
					label.verticalAlign("bottom");
				} else if (angle == 270) {
					label.horizontalAlign("right");
					label.verticalAlign("top");// ref.orientation == "lr" ?
												// "bottom" : "top");
				} else if (angle > 270 && angle <= 360) {
					label.horizontalAlign("right");
					label.verticalAlign("top");
				}
			}
			ref.iorientation = ref.iorientation || ref.orientation;
			ref.orientation = (label.verticalAlign() == "top" ? "u" : "l")
					+ (label.horizontalAlign() == "left" ? "l" : "r");
		}

		label.setReferencePoint(jQuery.extend({}, {
					intersection : intersection,
					segment : {
						from : from,
						fromIndex : this.dockers.indexOf(from),
						fromPosition : from.bounds.center(),
						to : to,
						toIndex : this.dockers.indexOf(to),
						toPosition : to.bounds.center()
					},
					dirty : dirty || false
				}, ref))
	},
	/**
	 * Adjusts the child shapes of an edges after a docker was removed.
	 * 
	 * @param{ORYX.Core.Controls.Docker} docker The removed docker.
	 */
	handleChildShapesAfterRemoveDocker : function(docker) {
		/* Ensure docker type */
		if (!(docker instanceof ORYX.Core.Controls.Docker)) {
			return;
		}

		this.attachedNodePositionData.each(function(nodePositionData) {
			if (nodePositionData.value.segment.docker1 === docker) {
				/* The new start of the segment is the predecessor of docker2. */
				var index = this.dockers
						.indexOf(nodePositionData.value.segment.docker2);
				if (index == -1) {
					return;
				}
				nodePositionData.value.segment.docker1 = this.dockers[index - 1];
			} else if (nodePositionData.value.segment.docker2 === docker) {
				/* The new end of the segment is the successor of docker1. */
				var index = this.dockers
						.indexOf(nodePositionData.value.segment.docker1);
				if (index == -1) {
					return;
				}
				nodePositionData.value.segment.docker2 = this.dockers[index + 1];
			}
		}.bind(this));

		// Update all labels reference points
		this.getLabels().each(function(label) {

			var ref = label.getReferencePoint();
			if (!ref) {
				return;
			}
			var from = ref.segment.from;
			var to = ref.segment.to;

			if (from !== docker && to !== docker) {
				return;
			}

			var segment = this.findSegment(ref.intersection);
			if (!segment) {
				from = segment.fromDocker;
				to = segment.toDocker;
			} else {
				from = from === docker ? this.dockers[this.dockers.indexOf(to)
						- 1] : from;
				to = this.dockers[this.dockers.indexOf(from) + 1];
			}

			var intersection = ORYX.Core.Math.getPointOfIntersectionPointLine(
					from.bounds.center(), to.bounds.center(), ref.intersection,
					true);
			// Update the reference point
			this.updateReferencePointOfLabel(label, intersection, from, to,
					true);
		}.bind(this));

		/* Update attached nodes visual representation */
		this.refreshAttachedNodes();
	},

	/**
	 * @deprecated Use the .createDocker() Method and set the point via the
	 *             bounds
	 */
	addDocker : function(position, exDocker) {
		var lastDocker;
		var result;
		this._dockersByPath.any((function(pair) {
			return pair.value.any((function(docker, index) {
				if (!lastDocker) {
					lastDocker = docker;
					return false;
				} else {
					var point1 = lastDocker.bounds.center();
					var point2 = docker.bounds.center();

					var additionalIEZoom = 1;
					if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
						var ua = navigator.userAgent;
						if (ua.indexOf('MSIE') >= 0) {
							// IE 10 and below
							var zoom = Math
									.round((screen.deviceXDPI / screen.logicalXDPI)
											* 100);
							if (zoom !== 100) {
								additionalIEZoom = zoom / 100
							}
						}
					}

					if (additionalIEZoom !== 1) {
						position.x = position.x / additionalIEZoom;
						position.y = position.y / additionalIEZoom;
					}

					if (ORYX.Core.Math.isPointInLine(position.x, position.y,
							point1.x, point1.y, point2.x, point2.y, 10)) {
						var path = this._paths.find(function(path) {
									return path.id === pair.key;
								});
						if (path) {
							var allowAttr = path.getAttributeNS(NAMESPACE_ORYX,
									'allowDockers');
							if (allowAttr && allowAttr.toLowerCase() === "no") {
								return true;
							}
						}

						var newDocker = (exDocker) ? exDocker : this
								.createDocker(this.dockers.indexOf(lastDocker)
												+ 1, position);
						newDocker.bounds.centerMoveTo(position);
						if (exDocker)
							this.add(newDocker, this.dockers
											.indexOf(lastDocker)
											+ 1);
						result = newDocker;
						return true;
					} else {
						lastDocker = docker;
						return false;
					}
				}
			}).bind(this));
		}).bind(this));
		return result;
	},

	removeDocker : function(docker) {
		if (this.dockers.length > 2 && !(this.dockers.first() === docker)) {
			this._dockersByPath.any((function(pair) {
						if (pair.value.member(docker)) {
							if (docker === pair.value.last()) {
								return true;
							} else {
								this.remove(docker);
								this._dockersByPath[pair.key] = pair.value
										.without(docker);
								this.isChanged = true;
								this._dockerChanged();
								return true;
							}
						}
						return false;
					}).bind(this));
		}
	},

	/**
	 * Removes all dockers from the edge which are on the line between two
	 * dockers
	 * 
	 * @return {Object} Removed dockers in an indicied array (key is the removed
	 *         position of the docker, value is docker themselve)
	 */
	removeUnusedDockers : function() {
		var marked = $H({});

		this.dockers.each(function(docker, i) {
			if (i == 0 || i == this.dockers.length - 1) {
				return
			}
			var previous = this.dockers[i - 1];

			/* Do not consider already removed dockers */
			if (marked.values().indexOf(previous) != -1 && this.dockers[i - 2]) {
				previous = this.dockers[i - 2];
			}
			var next = this.dockers[i + 1];

			var cp = previous.getDockedShape() && previous.referencePoint
					? previous.getAbsoluteReferencePoint()
					: previous.bounds.center();
			var cn = next.getDockedShape() && next.referencePoint ? next
					.getAbsoluteReferencePoint() : next.bounds.center();
			var cd = docker.bounds.center();

			if (ORYX.Core.Math.isPointInLine(cd.x, cd.y, cp.x, cp.y, cn.x,
					cn.y, 1)) {
				marked[i] = docker;
			}
		}.bind(this))

		marked.each(function(docker) {
					this.removeDocker(docker.value);
				}.bind(this))

		if (marked.values().length > 0) {
			this._update(true);
		}

		return marked;
	},

	/**
	 * Initializes the Edge after loading the SVG representation of the edge.
	 * 
	 * @param {SVGDocument}
	 *            svgDocument
	 */
	_init : function(svgDocument) {
		arguments.callee.$._init.apply(this, arguments);

		var minPointX, minPointY, maxPointX, maxPointY;

		// init markers
		var defs = svgDocument.getElementsByTagNameNS(NAMESPACE_SVG, "defs");
		if (defs.length > 0) {
			defs = defs[0];
			var markerElements = $A(defs.getElementsByTagNameNS(NAMESPACE_SVG,
					"marker"));
			var marker;
			var me = this;
			markerElements.each(function(markerElement) {
						try {
							marker = new ORYX.Core.SVG.SVGMarker(markerElement
									.cloneNode(true));
							me._markers[marker.id] = marker;
							var textElements = $A(marker.element
									.getElementsByTagNameNS(NAMESPACE_SVG,
											"text"));
							var label;
							textElements.each(function(textElement) {
										label = new ORYX.Core.SVG.Label({
													textElement : textElement,
													shapeId : this.id
												});
										me._labels[label.id] = label;
									});
						} catch (e) {
						}
					});
		}

		var gs = svgDocument.getElementsByTagNameNS(NAMESPACE_SVG, "g");
		if (gs.length <= 0) {
			throw "Edge: No g element found.";
		}
		var g = gs[0];

		g.setAttributeNS(null, "id", null);

		var isFirst = true;

		$A(g.childNodes).each((function(path, index) {
			if (ORYX.Editor.checkClassType(path, SVGPathElement)) {
				path = path.cloneNode(false);

				var pathId = this.id + "_" + index;
				path.setAttributeNS(null, "id", pathId);
				this._paths.push(path);

				// check, if markers are set and update the id
				var markersByThisPath = [];
				var markerUrl = path.getAttributeNS(null, "marker-start");

				if (markerUrl && markerUrl !== "") {
					markerUrl = markerUrl.strip();
					markerUrl = markerUrl.replace(/^url\(#/, '');

					var markerStartId = this.getValidMarkerId(markerUrl);
					path.setAttributeNS(null, "marker-start", "url(#"
									+ markerStartId + ")");

					markersByThisPath.push(this._markers[markerStartId]);
				}

				markerUrl = path.getAttributeNS(null, "marker-mid");

				if (markerUrl && markerUrl !== "") {
					markerUrl = markerUrl.strip();
					markerUrl = markerUrl.replace(/^url\(#/, '');
					var markerMidId = this.getValidMarkerId(markerUrl);
					path.setAttributeNS(null, "marker-mid", "url(#"
									+ markerMidId + ")");

					markersByThisPath.push(this._markers[markerMidId]);
				}

				markerUrl = path.getAttributeNS(null, "marker-end");

				if (markerUrl && markerUrl !== "") {
					markerUrl = markerUrl.strip();

					var markerEndId = this.getValidMarkerId(markerUrl);
					path.setAttributeNS(null, "marker-end", "url(#"
									+ markerEndId + ")");

					markersByThisPath.push(this._markers[markerEndId]);
				}

				this._markersByPath[pathId] = markersByThisPath;

				// init dockers
				var parser = new PathParser();
				var handler = new ORYX.Core.SVG.PointsPathHandler();
				parser.setHandler(handler);
				parser.parsePath(path);

				if (handler.points.length < 4) {
					throw "Edge: Path has to have two or more points specified.";
				}

				this._dockersByPath[pathId] = [];

				for (var i = 0; i < handler.points.length; i += 2) {
					// handler.points.each((function(point, pIndex){
					var x = handler.points[i];
					var y = handler.points[i + 1];
					if (isFirst || i > 0) {
						var docker = new ORYX.Core.Controls.Docker({
									eventHandlerCallback : this.eventHandlerCallback
								});
						docker.bounds.centerMoveTo(x, y);
						docker.bounds
								.registerCallback(this._dockerChangedCallback);
						this.add(docker, this.dockers.length);

						// this._dockersByPath[pathId].push(docker);

						// calculate minPoint and maxPoint
						if (minPointX) {
							minPointX = Math.min(x, minPointX);
							minPointY = Math.min(y, minPointY);
						} else {
							minPointX = x;
							minPointY = y;
						}

						if (maxPointX) {
							maxPointX = Math.max(x, maxPointX);
							maxPointY = Math.max(y, maxPointY);
						} else {
							maxPointX = x;
							maxPointY = y;
						}
					}
					// }).bind(this));
				}
				isFirst = false;
			}
		}).bind(this));

		this.bounds.set(minPointX, minPointY, maxPointX, maxPointY);

		if (false && (this.bounds.width() === 0 || this.bounds.height() === 0)) {
			var width = this.bounds.width();
			var height = this.bounds.height();

			this.bounds.extend({
						x : width === 0 ? 2 : 0,
						y : height === 0 ? 2 : 0
					});

			this.bounds.moveBy({
						x : width === 0 ? -1 : 0,
						y : height === 0 ? -1 : 0
					});

		}

		this._oldBounds = this.bounds.clone();

		// add paths to this.node
		this._paths.reverse();
		var paths = [];
		this._paths.each((function(path) {
					paths
							.push(this.node.childNodes[0].childNodes[0].childNodes[0]
									.appendChild(path));
				}).bind(this));

		this._paths = paths;

		// init interaction path
		this._paths.each((function(path) {
					var iPath = path.cloneNode(false);
					iPath.setAttributeNS(null, "id", undefined);
					iPath.setAttributeNS(null, "stroke-width", 10);
					iPath.setAttributeNS(null, "visibility", "hidden");
					iPath.setAttributeNS(null, "stroke-dasharray", null);
					iPath.setAttributeNS(null, "stroke", "black");
					iPath.setAttributeNS(null, "fill", "none");
					iPath.setAttributeNS(null, "title", this.getStencil()
									.title());
					this._interactionPaths
							.push(this.node.childNodes[0].childNodes[0].childNodes[0]
									.appendChild(iPath));
				}).bind(this));

		this._paths.reverse();
		this._interactionPaths.reverse();

		/** initialize labels */
		var textElems = svgDocument.getElementsByTagNameNS(
				ORYX.CONFIG.NAMESPACE_SVG, 'text');

		$A(textElems).each((function(textElem) {
					var label = new ORYX.Core.SVG.Label({
								textElement : textElem,
								shapeId : this.id
							});
					this.node.childNodes[0].childNodes[0]
							.appendChild(label.node);
					this._labels[label.id] = label;

					label.registerOnChange(this.layout.bind(this));
				}).bind(this));

		this.propertiesChanged.each(function(pair) {
					pair.value = true;
				});

		// if(this.dockers.length == 2) {

		// }

		// this._update(true);
	},

	getValidMarkerId : function(markerUrl) {
		if (markerUrl.indexOf("url(\"#") >= 0) {
			// Fix for IE9, additional quotes are added to the <id
			var rawId = markerUrl.replace(/^url\(\"#/, "").replace(/\"\)$/, '');
			return this.id + rawId;
		} else {
			markerUrl = markerUrl.replace(/^url\(#/, '');
			return this.id.concat(markerUrl.replace(/\)$/, ''));
		}
	},

	/**
	 * Adds all necessary markers of this Edge to the SVG document. Has to be
	 * called, while this.node is part of DOM.
	 */
	addMarkers : function(defs) {
		this._markers.each(function(marker) {
					if (!defs.ownerDocument.getElementById(marker.value.id)) {
						marker.value.element = defs
								.appendChild(marker.value.element);
					}
				});
	},

	/**
	 * Removes all necessary markers of this Edge from the SVG document. Has to
	 * be called, while this.node is part of DOM.
	 */
	removeMarkers : function() {
		var svgElement = this.node.ownerSVGElement;
		if (svgElement) {
			var defs = svgElement.getElementsByTagNameNS(NAMESPACE_SVG, "defs");
			if (defs.length > 0) {
				defs = defs[0];
				this._markers.each(function(marker) {
							var foundMarker = defs.ownerDocument
									.getElementById(marker.value.id);
							if (foundMarker) {
								marker.value.element = defs
										.removeChild(marker.value.element);
							}
						});
			}
		}
	},

	/**
	 * Calls when a docker has changed
	 */
	_dockerChanged : function() {

		// this._update(true);
		this._dockerUpdated = true;

	},

	serialize : function() {
		var result = arguments.callee.$.serialize.apply(this);

		// add dockers triple
		var value = "";
		this._dockersByPath.each((function(pair) {
					pair.value.each(function(docker) {
								var position = docker.getDockedShape()
										&& docker.referencePoint
										? docker.referencePoint
										: docker.bounds.center();
								value = value.concat(position.x + " "
										+ position.y + " ");
							});

					value += " # ";
				}).bind(this));
		result.push({
					name : 'dockers',
					prefix : 'oryx',
					value : value,
					type : 'literal'
				});

		// add parent triple dependant on the dockedShapes
		// TODO change this when canvas becomes a resource
		/*
		 * var source = this.dockers.first().getDockedShape(); var target =
		 * this.dockers.last().getDockedShape(); var sharedParent; if (source &&
		 * target) { //get shared parent while (source.parent) { source =
		 * source.parent; if (source instanceof ORYX.Core.Canvas) { sharedParent =
		 * source; break; } else { var targetParent = target.parent; var found;
		 * while (targetParent) { if (source === targetParent) { sharedParent =
		 * source; found = true; break; } else { targetParent =
		 * targetParent.parent; } } if (found) { break; } } } } else if (source) {
		 * sharedParent = source.parent; } else if (target) { sharedParent =
		 * target.parent; }
		 */
		// if (sharedParent) {
		/*
		 * result.push({ name: 'parent', prefix: 'raziel', //value: '#' +
		 * ERDF.__stripHashes(sharedParent.resourceId), value: '#' +
		 * ERDF.__stripHashes(this.getCanvas().resourceId), type: 'resource' });
		 */
		// }
		// serialize target and source
		var lastDocker = this.dockers.last();

		var target = lastDocker.getDockedShape();

		if (target) {
			result.push({
						name : 'target',
						prefix : 'raziel',
						value : '#' + ERDF.__stripHashes(target.resourceId),
						type : 'resource'
					});
		}

		try {
			// result = this.getStencil().serialize(this, result);
			var serializeEvent = this.getStencil().serialize();

			/*
			 * call serialize callback by reference, result should be found in
			 * serializeEvent.result
			 */
			if (serializeEvent.type) {
				serializeEvent.shape = this;
				serializeEvent.data = result;
				serializeEvent.result = undefined;
				serializeEvent.forceExecution = true;

				this._delegateEvent(serializeEvent);

				if (serializeEvent.result) {
					result = serializeEvent.result;
				}
			}
		} catch (e) {
		}
		return result;
	},

	deserialize : function(data) {
		try {
			// data = this.getStencil().deserialize(this, data);

			var deserializeEvent = this.getStencil().deserialize();

			/*
			 * call serialize callback by reference, result should be found in
			 * serializeEventInfo.result
			 */
			if (deserializeEvent.type) {
				deserializeEvent.shape = this;
				deserializeEvent.data = data;
				deserializeEvent.result = undefined;
				deserializeEvent.forceExecution = true;

				this._delegateEvent(deserializeEvent);
				if (deserializeEvent.result) {
					data = deserializeEvent.result;
				}
			}
		} catch (e) {
		}

		// Set the outgoing shapes
		var target = data.find(function(ser) {
					return (ser.prefix + "-" + ser.name) == 'raziel-target'
				});
		var targetShape;
		if (target) {
			targetShape = this.getCanvas()
					.getChildShapeByResourceId(target.value);
		}

		var outgoing = data.findAll(function(ser) {
					return (ser.prefix + "-" + ser.name) == 'raziel-outgoing'
				});
		outgoing.each((function(obj) {
					// TODO: Look at Canvas
					if (!this.parent) {
						return
					};

					// Set outgoing Shape
					var next = this.getCanvas()
							.getChildShapeByResourceId(obj.value);

					if (next) {
						if (next == targetShape) {
							// If this is an edge, set the last docker to the
							// next shape
							this.dockers.last().setDockedShape(next);
							this.dockers.last().setReferencePoint({
										x : next.bounds.width() / 2.0,
										y : next.bounds.height() / 2.0
									});
						} else if (next instanceof ORYX.Core.Edge) {
							// Set the first docker of the next shape
							next.dockers.first().setDockedShape(this);
							// next.dockers.first().setReferencePoint({x:
							// this.bounds.width() / 2.0, y:
							// this.bounds.height() / 2.0});
						} /*
							 * else if(next.dockers.length > 0) { //next is a
							 * node and next has a docker
							 * next.dockers.first().setDockedShape(this);
							 * next.dockers.first().setReferencePoint({x:
							 * this.bounds.width() / 2.0, y:
							 * this.bounds.height() / 2.0}); }
							 */
					}

				}).bind(this));

		var oryxDockers = data.find(function(obj) {
					return (obj.prefix === "oryx" && obj.name === "dockers");
				});

		if (oryxDockers) {
			var dataByPath = oryxDockers.value.split("#").without("")
					.without(" ");

			dataByPath.each((function(data, index) {
				var values = data.replace(/,/g, " ").split(" ").without("");

				// for each docker two values must be defined
				if (values.length % 2 === 0) {
					var path = this._paths[index];

					if (path) {
						if (index === 0) {
							while (this._dockersByPath[path.id].length > 2) {
								this
										.removeDocker(this._dockersByPath[path.id][1]);
							}
						} else {
							while (this._dockersByPath[path.id].length > 1) {
								this
										.removeDocker(this._dockersByPath[path.id][0]);
							}
						}

						var dockersByPath = this._dockersByPath[path.id];

						if (index === 0) {
							// set position of first docker
							var x = parseFloat(values.shift());
							var y = parseFloat(values.shift());

							if (dockersByPath.first().getDockedShape()) {
								dockersByPath.first().setReferencePoint({
											x : x,
											y : y
										});
							} else {
								dockersByPath.first().bounds.centerMoveTo(x, y);
							}
						}

						// set position of last docker
						y = parseFloat(values.pop());
						x = parseFloat(values.pop());

						if (dockersByPath.last().getDockedShape()) {
							dockersByPath.last().setReferencePoint({
										x : x,
										y : y
									});
						} else {
							dockersByPath.last().bounds.centerMoveTo(x, y);
						}

						// add additional dockers
						for (var i = 0; i < values.length; i++) {
							x = parseFloat(values[i]);
							y = parseFloat(values[++i]);

							var newDocker = this.createDocker();
							newDocker.bounds.centerMoveTo(x, y);

							// this.dockers = this.dockers.without(newDocker);
							// this.dockers.splice(this.dockers.indexOf(dockersByPath.last()),
							// 0, newDocker);
							// dockersByPath.splice(this.dockers.indexOf(dockersByPath.last()),
							// 0, newDocker);
						}
					}
				}
			}).bind(this));
		} else {
			this.alignDockers();
		}

		arguments.callee.$.deserialize.apply(this, arguments);

		this._changed();
	},

	toString : function() {
		return this.getStencil().title() + " " + this.id;
	},

	/**
	 * @return {ORYX.Core.Shape} Returns last docked shape or null.
	 */
	getTarget : function() {
		return this.dockers.last()
				? this.dockers.last().getDockedShape()
				: null;
	},

	/**
	 * @return {ORYX.Core.Shape} Returns the first docked shape or null
	 */
	getSource : function() {
		return this.dockers.first()
				? this.dockers.first().getDockedShape()
				: null;
	},

	/**
	 * Checks whether the edge is at least docked to one shape.
	 * 
	 * @return {boolean} True if edge is docked
	 */
	isDocked : function() {
		var isDocked = false;
		this.dockers.each(function(docker) {
					if (docker.isDocked()) {
						isDocked = true;
						throw $break;
					}
				});
		return isDocked;
	},

	/**
	 * Calls {@link ORYX.Core.AbstractShape#toJSON} and add a some stencil set
	 * information.
	 */
	toJSON : function() {
		var json = arguments.callee.$.toJSON.apply(this, arguments);

		if (this.getTarget()) {
			json.target = {
				resourceId : this.getTarget().resourceId
			};
		}

		return json;
	}
};
ORYX.Core.Edge = ORYX.Core.Shape.extend(ORYX.Core.Edge);
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX) {
	var ORYX = {}
}
if (!ORYX.Plugins) {
	ORYX.Plugins = {}
}

/**
 * This abstract plugin class can be used to build plugins on. It provides some
 * more basic functionality like registering events (on*-handlers)...
 * 
 * @example
 * ORYX.Plugins.MyPlugin = ORYX.Plugins.AbstractPlugin.extend({
 construct: function() {
 // Call super class constructor
 arguments.callee.$.construct.apply(this, arguments);
 * 
 * [...]
 },
 [...]
 });
 * 
 * @class ORYX.Plugins.AbstractPlugin
 * @constructor Creates a new instance
 * @author Willi Tscheschner
 */
ORYX.Plugins.AbstractPlugin = Clazz.extend({
	/**
	 * The facade which offer editor-specific functionality
	 * 
	 * @type Facade
	 * @memberOf ORYX.Plugins.AbstractPlugin.prototype
	 */
	facade : null,

	construct : function(facade) {
		this.facade = facade;

		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, this.onLoaded
						.bind(this));
	},

	/**
	 * Overwrite to handle load event. TODO: Document params!!!
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 */
	onLoaded : function() {
	},

	/**
	 * Overwrite to handle selection changed event. TODO: Document params!!!
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 */
	onSelectionChanged : function() {
	},

	/**
	 * Show overlay on given shape.
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 *           @example
	 *           showOverlay(
	       myShape,
	       { stroke: "green" },
	       ORYX.Editor.graft("http://www.w3.org/2000/svg", null, ['path', {
	           "title": "Click the element to execute it!",
	           "stroke-width": 2.0,
	           "stroke": "black",
	           "d": "M0,-5 L5,0 L0,5 Z",
	           "line-captions": "round"
	       }])
	   )
	 * @param {Oryx.XXX.Shape[]}
	 *            shapes One shape or array of shapes the overlay should be put
	 *            on
	 * @param {Oryx.XXX.Attributes}
	 *            attributes some attributes...
	 * @param {Oryx.svg.node}
	 *            svgNode The svg node which should be used as overlay
	 * @param {String}
	 *            [svgNode="NW"] The svg node position where the overlay should
	 *            be placed
	 */
	showOverlay : function(shapes, attributes, svgNode, svgNodePosition) {

		if (!(shapes instanceof Array)) {
			shapes = [shapes]
		}

		// Define Shapes
		shapes = shapes.map(function(shape) {
					var el = shape;
					if (typeof shape == "string") {
						el = this.facade.getCanvas()
								.getChildShapeByResourceId(shape);
						el = el
								|| this.facade.getCanvas().getChildById(shape,
										true);
					}
					return el;
				}.bind(this)).compact();

		// Define unified id
		if (!this.overlayID) {
			this.overlayID = this.type + ORYX.Editor.provideId();
		}

		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_OVERLAY_SHOW,
					id : this.overlayID,
					shapes : shapes,
					attributes : attributes,
					node : svgNode,
					nodePosition : svgNodePosition || "NW"
				});

	},

	/**
	 * Hide current overlay.
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 */
	hideOverlay : function() {
		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_OVERLAY_HIDE,
					id : this.overlayID
				});
	},

	/**
	 * Does a transformation with the given xslt stylesheet.
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 * @param {String}
	 *            data The data (e.g. eRDF) which should be transformed
	 * @param {String}
	 *            stylesheet URL of a stylesheet which should be used for
	 *            transforming data.
	 */
	doTransform : function(data, stylesheet) {

		if (!stylesheet || !data) {
			return ""
		}

		var parser = new DOMParser();
		var parsedData = parser.parseFromString(data, "text/xml");
		source = stylesheet;
		new Ajax.Request(source, {
					asynchronous : false,
					method : 'get',
					onSuccess : function(transport) {
						xsl = transport.responseText
					}.bind(this),
					onFailure : (function(transport) {
						ORYX.Log.error("XSL load failed" + transport);
					}).bind(this)
				});
		var xsltProcessor = new XSLTProcessor();
		var domParser = new DOMParser();
		var xslObject = domParser.parseFromString(xsl, "text/xml");
		xsltProcessor.importStylesheet(xslObject);

		try {

			var newData = xsltProcessor.transformToFragment(parsedData,
					document);
			var serializedData = (new XMLSerializer())
					.serializeToString(newData);

			/* Firefox 2 to 3 problem?! */
			serializedData = !serializedData.startsWith("<?xml")
					? "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
							+ serializedData
					: serializedData;

			return serializedData;

		} catch (error) {
			return -1;
		}

	},

	/**
	 * Opens a new window that shows the given XML content.
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 * @param {Object}
	 *            content The XML content to be shown.
	 *            @example
	 *            openDownloadWindow( "my.xml", "<exampleXML />" );
	 */
	openXMLWindow : function(content) {
		var win = window.open('data:application/xml,'
						+ encodeURIComponent(content), '_blank',
				"resizable=yes,width=600,height=600,toolbar=0,scrollbars=yes");
	},

	/**
	 * Opens a download window for downloading the given content.
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 * @param {String}
	 *            filename The content's file name
	 * @param {String}
	 *            content The content to download
	 */
	openDownloadWindow : function(filename, content) {
		var win = window.open("");
		if (win != null) {
			win.document.open();
			win.document.write("<html><body>");
			var submitForm = win.document.createElement("form");
			win.document.body.appendChild(submitForm);

			var createHiddenElement = function(name, value) {
				var newElement = document.createElement("input");
				newElement.name = name;
				newElement.type = "hidden";
				newElement.value = value;
				return newElement
			}

			submitForm.appendChild(createHiddenElement("download", content));
			submitForm.appendChild(createHiddenElement("file", filename));

			submitForm.method = "POST";
			win.document.write("</body></html>");
			win.document.close();
			submitForm.action = ORYX.PATH + "/download";
			submitForm.submit();
		}
	},

	/**
	 * Serializes DOM.
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 * @type {String} Serialized DOM
	 */
	getSerializedDOM : function() {
		// Force to set all resource IDs
		var serializedDOM = DataManager.serializeDOM(this.facade);

		// add namespaces
		serializedDOM = '<?xml version="1.0" encoding="utf-8"?>'
				+ '<html xmlns="http://www.w3.org/1999/xhtml" '
				+ 'xmlns:b3mn="http://b3mn.org/2007/b3mn" '
				+ 'xmlns:ext="http://b3mn.org/2007/ext" '
				+ 'xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" '
				+ 'xmlns:atom="http://b3mn.org/2007/atom+xhtml">'
				+ '<head profile="http://purl.org/NET/erdf/profile">'
				+ '<link rel="schema.dc" href="http://purl.org/dc/elements/1.1/" />'
				+ '<link rel="schema.dcTerms" href="http://purl.org/dc/terms/ " />'
				+ '<link rel="schema.b3mn" href="http://b3mn.org" />'
				+ '<link rel="schema.oryx" href="http://oryx-editor.org/" />'
				+ '<link rel="schema.raziel" href="http://raziel.org/" />'
				+ '<base href="' + location.href.split("?")[0] + '" />'
				+ '</head><body>' + serializedDOM + '</body></html>';

		return serializedDOM;
	},

	/**
	 * Sets the editor in read only mode: Edges/ dockers cannot be moved
	 * anymore, shapes cannot be selected anymore.
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 */
	enableReadOnlyMode : function() {
		// Edges cannot be moved anymore
		this.facade.disableEvent(ORYX.CONFIG.EVENT_MOUSEDOWN);

		// Stop the user from editing the diagram while the plugin is active
		this._stopSelectionChange = function() {
			if (this.facade.getSelection().length > 0) {
				this.facade.setSelection([]);
			}
		};
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED,
				this._stopSelectionChange.bind(this));
	},
	/**
	 * Disables read only mode, see
	 * 
	 * @see
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 * @see ORYX.Plugins.AbstractPlugin.prototype.enableReadOnlyMode
	 */
	disableReadOnlyMode : function() {
		// Edges can be moved now again
		this.facade.enableEvent(ORYX.CONFIG.EVENT_MOUSEDOWN);

		if (this._stopSelectionChange) {
			this.facade.unregisterOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED,
					this._stopSelectionChange.bind(this));
			this._stopSelectionChange = undefined;
		}
	},

	/**
	 * Extracts RDF from DOM.
	 * 
	 * @methodOf ORYX.Plugins.AbstractPlugin.prototype
	 * @type {String} Extracted RFD. Null if there are transformation errors.
	 */
	getRDFFromDOM : function() {
		// convert to RDF
		try {
			var xsl = "";
			source = ORYX.PATH + "lib/extract-rdf.xsl";
			new Ajax.Request(source, {
						asynchronous : false,
						method : 'get',
						onSuccess : function(transport) {
							xsl = transport.responseText
						}.bind(this),
						onFailure : (function(transport) {
							ORYX.Log.error("XSL load failed" + transport);
						}).bind(this)
					});

			var domParser = new DOMParser();
			var xmlObject = domParser.parseFromString(this.getSerializedDOM(),
					"text/xml");
			var xslObject = domParser.parseFromString(xsl, "text/xml");
			var xsltProcessor = new XSLTProcessor();
			xsltProcessor.importStylesheet(xslObject);
			var result = xsltProcessor.transformToFragment(xmlObject, document);

			var serializer = new XMLSerializer();

			return serializer.serializeToString(result);
		} catch (e) {
			console.log("error serializing " + e);
			return "";
		}

	},

	/**
	 * Checks if a certain stencil set is loaded right now.
	 * 
	 */
	isStencilSetExtensionLoaded : function(stencilSetExtensionNamespace) {
		return this.facade.getStencilSets().values().any(function(ss) {
					return ss.extensions().keys().any(function(extensionKey) {
								return extensionKey == stencilSetExtensionNamespace;
							}.bind(this));
				}.bind(this));
	},

	/**
	 * Raises an event so that registered layouters does have the posiblility to
	 * layout the given shapes For further reading, have a look into the
	 * AbstractLayouter class
	 * 
	 * @param {Object}
	 *            shapes
	 */
	doLayout : function(shapes) {
		// Raises a do layout event
		if (this.facade.raiseEvent) {
			this.facade.raiseEvent({
						type : ORYX.CONFIG.EVENT_LAYOUT,
						shapes : shapes
					});
		} else {
			this.facade.handleEvents({
						type : ORYX.CONFIG.EVENT_LAYOUT,
						shapes : shapes
					});
		}
	},

	/**
	 * Does a primitive layouting with the incoming/outgoing edges (set the
	 * dockers to the right position) and if necessary, it will be called the
	 * real layouting
	 * 
	 * @param {ORYX.Core.Node}
	 *            node
	 * @param {Array}
	 *            edges
	 */
	layoutEdges : function(node, allEdges, offset) {

		if (!this.facade.isExecutingCommands()) {
			return
		}

		var Command = ORYX.Core.Command.extend({
			construct : function(edges, node, offset, plugin) {
				this.edges = edges;
				this.node = node;
				this.plugin = plugin;
				this.offset = offset;

				// Get the new absolute center
				var center = node.absoluteXY();
				this.ulo = {
					x : center.x - offset.x,
					y : center.y - offset.y
				};

			},
			execute : function() {

				if (this.changes) {
					this.executeAgain();
					return;
				} else {
					this.changes = [];
					this.edges.each(function(edge) {
								this.changes.push({
											edge : edge,
											oldDockerPositions : edge.dockers
													.map(function(r) {
																return r.bounds
																		.center()
															})
										})
							}.bind(this));
				}

				// Find all edges, which are related to the node and
				// have more than two dockers
				this.edges
						// Find all edges with more than two dockers
						.findAll(function(r) {
									return r.dockers.length > 2
								}.bind(this))
						// For every edge, check second and one before last
						// docker
						// if there are horizontal/vertical on the same level
						// and if so, align the the bounds
						.each(function(edge) {
							if (edge.dockers.first().getDockedShape() === this.node) {
								var second = edge.dockers[1];
								if (this.align(second.bounds, edge.dockers
												.first())) {
									second.update();
								}
							} else if (edge.dockers.last().getDockedShape() === this.node) {
								var beforeLast = edge.dockers[edge.dockers.length
										- 2];
								if (this.align(beforeLast.bounds, edge.dockers
												.last())) {
									beforeLast.update();
								}
							}
							edge._update(true);
							edge.removeUnusedDockers();
							if (this.isBendPointIncluded(edge)) {
								this.plugin.doLayout(edge);
								return;
							}
						}.bind(this));

				// Find all edges, which have only to dockers
				// and is located horizontal/vertical.
				// Do layout with those edges
				this.edges
						// Find all edges with exactly two dockers
						.each(function(edge) {
							if (edge.dockers.length == 2) {
								var p1 = edge.dockers.first()
										.getAbsoluteReferencePoint()
										|| edge.dockers.first().bounds.center();
								var p2 = edge.dockers.last()
										.getAbsoluteReferencePoint()
										|| edge.dockers.first().bounds.center();
								// Find all horizontal/vertical edges
								if (Math.abs(-Math.abs(p1.x - p2.x)
										+ Math.abs(this.offset.x)) < 2
										|| Math.abs(-Math.abs(p1.y - p2.y)
												+ Math.abs(this.offset.y)) < 2) {
									this.plugin.doLayout(edge);
								}
							}
						}.bind(this));

				this.edges.each(function(edge, i) {
							this.changes[i].dockerPositions = edge.dockers.map(
									function(r) {
										return r.bounds.center()
									});
						}.bind(this));

			},
			/**
			 * Align the bounds if the center is the same than the old center
			 * 
			 * @params {Object} bounds
			 * @params {Object} bounds2
			 */
			align : function(bounds, refDocker) {

				var abRef = refDocker.getAbsoluteReferencePoint()
						|| refDocker.bounds.center();

				var xdif = bounds.center().x - abRef.x;
				var ydif = bounds.center().y - abRef.y;
				if (Math.abs(-Math.abs(xdif) + Math.abs(this.offset.x)) < 3
						&& this.offset.xs === undefined) {
					bounds.moveBy({
								x : -xdif,
								y : 0
							})
				}
				if (Math.abs(-Math.abs(ydif) + Math.abs(this.offset.y)) < 3
						&& this.offset.ys === undefined) {
					bounds.moveBy({
								y : -ydif,
								x : 0
							})
				}

				if (this.offset.xs !== undefined
						|| this.offset.ys !== undefined) {
					var absPXY = refDocker.getDockedShape().absoluteXY();
					xdif = bounds.center().x
							- (absPXY.x + ((abRef.x - absPXY.x) / this.offset.xs));
					ydif = bounds.center().y
							- (absPXY.y + ((abRef.y - absPXY.y) / this.offset.ys));

					if (Math.abs(-Math.abs(xdif) + Math.abs(this.offset.x)) < 3) {
						bounds.moveBy({
									x : -(bounds.center().x - abRef.x),
									y : 0
								})
					}

					if (Math.abs(-Math.abs(ydif) + Math.abs(this.offset.y)) < 3) {
						bounds.moveBy({
									y : -(bounds.center().y - abRef.y),
									x : 0
								})
					}
				}
			},

			/**
			 * Returns a TRUE if there are bend point which overlay the shape
			 */
			isBendPointIncluded : function(edge) {
				// Get absolute bounds
				var ab = edge.dockers.first().getDockedShape();
				var bb = edge.dockers.last().getDockedShape();

				if (ab) {
					ab = ab.absoluteBounds();
					ab.widen(5);
				}

				if (bb) {
					bb = bb.absoluteBounds();
					bb.widen(20); // Wide with 20 because of the arrow from
									// the edge
				}

				return edge.dockers.any(function(docker, i) {
							var c = docker.bounds.center();
							// Dont count first and last
							return i != 0
									&& i != edge.dockers.length - 1
									&&
									// Check if the point is included to the
									// absolute bounds
									((ab && ab.isIncluded(c)) || (bb && bb
											.isIncluded(c)))
						})
			},

			removeAllDocker : function(edge) {
				edge.dockers.slice(1, edge.dockers.length - 1).each(
						function(docker) {
							edge.removeDocker(docker);
						})
			},
			executeAgain : function() {
				this.changes.each(function(change) {
							// Reset the dockers
							this.removeAllDocker(change.edge);
							change.dockerPositions.each(function(pos, i) {
										if (i == 0
												|| i == change.dockerPositions.length
														- 1) {
											return
										}
										var docker = change.edge.createDocker(
												undefined, pos);
										docker.bounds.centerMoveTo(pos);
										docker.update();
									}.bind(this));
							change.edge._update(true);
						}.bind(this));
			},
			rollback : function() {
				this.changes.each(function(change) {
					// Reset the dockers
					this.removeAllDocker(change.edge);
					change.oldDockerPositions.each(function(pos, i) {
						if (i == 0 || i == change.oldDockerPositions.length - 1) {
							return
						}
						var docker = change.edge.createDocker(undefined, pos);
						docker.bounds.centerMoveTo(pos);
						docker.update();
					}.bind(this));
					change.edge._update(true);
				}.bind(this));
			}
		});

		this.facade
				.executeCommands([new Command(allEdges, node, offset, this)]);

	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX) {
	var ORYX = {}
}
if (!ORYX.Plugins) {
	ORYX.Plugins = {}
}

/**
 * This abstract plugin implements the core behaviour of layout
 * 
 * @class ORYX.Plugins.AbstractLayouter
 * @constructor Creates a new instance
 * @author Willi Tscheschner
 */
ORYX.Plugins.AbstractLayouter = ORYX.Plugins.AbstractPlugin.extend({

			/**
			 * 'layouted' defined all types of shapes which will be layouted. It
			 * can be one value or an array of values. The value can be a
			 * Stencil ID (as String) or an class type of either a
			 * ORYX.Core.Node or ORYX.Core.Edge
			 * 
			 * @type Array|String|Object
			 * @memberOf ORYX.Plugins.AbstractLayouter.prototype
			 */
			layouted : [],

			/**
			 * Constructor
			 * 
			 * @param {Object}
			 *            facade
			 * @memberOf ORYX.Plugins.AbstractLayouter.prototype
			 */
			construct : function(facade) {
				arguments.callee.$.construct.apply(this, arguments);

				this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LAYOUT,
						this._initLayout.bind(this));
			},

			/**
			 * Proofs if this shape should be layouted or not
			 * 
			 * @param {Object}
			 *            shape
			 * @memberOf ORYX.Plugins.AbstractLayouter.prototype
			 */
			isIncludedInLayout : function(shape) {
				if (!(this.layouted instanceof Array)) {
					this.layouted = [this.layouted].compact();
				}

				// If there are no elements
				if (this.layouted.length <= 0) {
					// Return TRUE
					return true;
				}

				// Return TRUE if there is any correlation between
				// the 'layouted' attribute and the shape themselve.
				return this.layouted.any(function(s) {
							if (typeof s == "string") {
								return shape.getStencil().id().include(s);
							} else {
								return shape instanceof s;
							}
						})
			},

			/**
			 * Callback to start the layouting
			 * 
			 * @param {Object}
			 *            event Layout event
			 * @param {Object}
			 *            shapes Given shapes
			 * @memberOf ORYX.Plugins.AbstractLayouter.prototype
			 */
			_initLayout : function(event) {

				// Get the shapes
				var shapes = [event.shapes].flatten().compact();

				// Find all shapes which should be layouted
				var toLayout = shapes.findAll(function(shape) {
							return this.isIncludedInLayout(shape)
						}.bind(this))

				// If there are shapes left
				if (toLayout.length > 0) {
					// Do layout
					this.layout(toLayout);
				}
			},

			/**
			 * Implementation of layouting a set on shapes
			 * 
			 * @param {Object}
			 *            shapes Given shapes
			 * @memberOf ORYX.Plugins.AbstractLayouter.prototype
			 */
			layout : function(shapes) {
				throw new Error("Layouter has to implement the layout function.")
			}
		});/*
			 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
			 * License rights for this program may be obtained from Alfresco
			 * Software, Ltd. pursuant to a written agreement and any use of
			 * this program without such an agreement is prohibited.
			 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.Edit = Clazz.extend({

	construct : function(facade) {

		this.facade = facade;
		this.clipboard = new ORYX.Plugins.Edit.ClipBoard();

		// this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN,
		// this.keyHandler.bind(this));

		this.facade.offer({
					name : ORYX.I18N.Edit.cut,
					description : ORYX.I18N.Edit.cutDesc,
					icon : ORYX.PATH + "images/cut.png",
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : 88,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.callEdit.bind(this, this.editCut),
					group : ORYX.I18N.Edit.group,
					index : 1,
					minShape : 1
				});

		this.facade.offer({
					name : ORYX.I18N.Edit.copy,
					description : ORYX.I18N.Edit.copyDesc,
					icon : ORYX.PATH + "images/page_copy.png",
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : 67,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.callEdit.bind(this, this.editCopy, [
									true, false]),
					group : ORYX.I18N.Edit.group,
					index : 2,
					minShape : 1
				});

		this.facade.offer({
					name : ORYX.I18N.Edit.paste,
					description : ORYX.I18N.Edit.pasteDesc,
					icon : ORYX.PATH + "images/page_paste.png",
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : 86,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.callEdit.bind(this, this.editPaste),
					isEnabled : this.clipboard.isOccupied.bind(this.clipboard),
					group : ORYX.I18N.Edit.group,
					index : 3,
					minShape : 0,
					maxShape : 0
				});

		this.facade.offer({
					name : ORYX.I18N.Edit.del,
					description : ORYX.I18N.Edit.delDesc,
					icon : ORYX.PATH + "images/cross.png",
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : 8,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}, {
								keyCode : 46,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.callEdit.bind(this, this.editDelete),
					group : ORYX.I18N.Edit.group,
					index : 4,
					minShape : 1
				});
	},

	callEdit : function(fn, args) {
		window.setTimeout(function() {
					fn.apply(this, (args instanceof Array ? args : []));
				}.bind(this), 1);
	},

	/**
	 * Handles the mouse down event and starts the copy-move-paste action, if
	 * control or meta key is pressed.
	 */
	handleMouseDown : function(event) {
		if (this._controlPressed) {
			this._controlPressed = false;
			this.editCopy();
			// console.log("copiedEle: %0",this.clipboard.shapesAsJson)
			// console.log("mousevent: %o",event)
			this.editPaste();
			event.forceExecution = true;
			this.facade.raiseEvent(event, this.clipboard.shapesAsJson);

		}
	},

	/**
	 * The key handler for this plugin. Every action from the set of cut, copy,
	 * paste and delete should be accessible trough simple keyboard shortcuts.
	 * This method checks whether any event triggers one of those actions.
	 * 
	 * @param {Object}
	 *            event The keyboard event that should be analysed for
	 *            triggering of this plugin.
	 */
	// keyHandler: function(event){
	// //TODO document what event.which is.
	//        
	// ORYX.Log.debug("edit.js handles a keyEvent.");
	//        
	// // assure we have the current event.
	// if (!event)
	// event = window.event;
	//        
	//        
	// // get the currently pressed key and state of control key.
	// var pressedKey = event.which || event.keyCode;
	// var ctrlPressed = event.ctrlKey;
	//        
	// // if the object is to be deleted, do so, and return immediately.
	// if ((pressedKey == ORYX.CONFIG.KEY_CODE_DELETE) ||
	// ((pressedKey == ORYX.CONFIG.KEY_CODE_BACKSPACE) &&
	// (event.metaKey || event.appleMetaKey))) {
	//        
	// ORYX.Log.debug("edit.js deletes the shape.");
	// this.editDelete();
	// return;
	// }
	//        
	// // if control key is not pressed, we're not interested anymore.
	// if (!ctrlPressed)
	// return;
	//         
	// // when ctrl is pressed, switch trough the possibilities.
	// switch (pressedKey) {
	//         
	// // cut.
	// case ORYX.CONFIG.KEY_CODE_X:
	// this.editCut();
	// break;
	//	         
	// // copy.
	// case ORYX.CONFIG.KEY_CODE_C:
	// this.editCopy();
	// break;
	//	         
	// // paste.
	// case ORYX.CONFIG.KEY_CODE_V:
	// this.editPaste();
	// break;
	// }
	// },
	/**
	 * Returns a list of shapes which should be considered while copying.
	 * Besides the shapes of given ones, edges and attached nodes are added to
	 * the result set. If one of the given shape is a child of another given
	 * shape, it is not put into the result.
	 */
	getAllShapesToConsider : function(shapes) {
		var shapesToConsider = []; // only top-level shapes
		var childShapesToConsider = []; // all child shapes of top-level shapes

		shapes.each(function(shape) {
					// Throw away these shapes which have a parent in given
					// shapes
					isChildShapeOfAnother = shapes.any(function(s2) {
								return s2.hasChildShape(shape);
							});
					if (isChildShapeOfAnother)
						return;

					// This shape should be considered
					shapesToConsider.push(shape);
					// Consider attached nodes (e.g. intermediate events)
					if (shape instanceof ORYX.Core.Node) {
						var attached = shape.getOutgoingNodes();
						attached = attached.findAll(function(a) {
									return !shapes.include(a)
								});
						shapesToConsider = shapesToConsider.concat(attached);
					}

					childShapesToConsider = childShapesToConsider.concat(shape
							.getChildShapes(true));
				}.bind(this));

		// All edges between considered child shapes should be considered
		// Look for these edges having incoming and outgoing in
		// childShapesToConsider
		var edgesToConsider = this.facade.getCanvas().getChildEdges().select(
				function(edge) {
					// Ignore if already added
					if (shapesToConsider.include(edge))
						return false;
					// Ignore if there are no docked shapes
					if (edge.getAllDockedShapes().size() === 0)
						return false;
					// True if all docked shapes are in considered child shapes
					return edge.getAllDockedShapes().all(function(shape) {
						// Remember: Edges can have other edges on outgoing,
						// that is why edges must not be included in
						// childShapesToConsider
						return shape instanceof ORYX.Core.Edge
								|| childShapesToConsider.include(shape);
					});
				});
		shapesToConsider = shapesToConsider.concat(edgesToConsider);

		return shapesToConsider;
	},

	/**
	 * Performs the cut operation by first copy-ing and then deleting the
	 * current selection.
	 */
	editCut : function() {
		// TODO document why this returns false.
		// TODO document what the magic boolean parameters are supposed to do.

		this.editCopy(false, true);
		this.editDelete(true);
		return false;
	},

	/**
	 * Performs the copy operation.
	 * 
	 * @param {Object}
	 *            will_not_update ??
	 */
	editCopy : function(will_update, useNoOffset) {
		var selection = this.facade.getSelection();

		// if the selection is empty, do not remove the previously copied
		// elements
		if (selection.length == 0)
			return;

		this.clipboard.refresh(selection, this
						.getAllShapesToConsider(selection), this.facade
						.getCanvas().getStencil().stencilSet().namespace(),
				useNoOffset);

		if (will_update)
			this.facade.updateSelection();
	},

	/**
	 * Performs the paste operation.
	 */
	editPaste : function() {
		// Create a new canvas with childShapes
		// and stencilset namespace to be JSON Import conform
		var canvas = {
			childShapes : this.clipboard.shapesAsJson,
			stencilset : {
				namespace : this.clipboard.SSnamespace
			}
		};
		// Apply json helper to iterate over json object
		jQuery.extend(canvas, ORYX.Core.AbstractShape.JSONHelper);

		var childShapeResourceIds = canvas.getChildShapes(true)
				.pluck("resourceId");
		var outgoings = {};
		// Iterate over all shapes
		canvas.eachChild(function(shape, parent) {
					// Throw away these references where referenced shape isn't
					// copied
					shape.outgoing = shape.outgoing.select(function(out) {
								return childShapeResourceIds
										.include(out.resourceId);
							});
					shape.outgoing.each(function(out) {
								if (!outgoings[out.resourceId]) {
									outgoings[out.resourceId] = [];
								}
								outgoings[out.resourceId].push(shape);
							});

					return shape;
				}.bind(this), true, true);

		// Iterate over all shapes
		canvas.eachChild(function(shape, parent) {

			// Check if there has a valid target
			if (shape.target
					&& !(childShapeResourceIds.include(shape.target.resourceId))) {
				shape.target = undefined;
				shape.targetRemoved = true;
			}

			// Check if the first docker is removed
			if (shape.dockers
					&& shape.dockers.length >= 1
					&& shape.dockers[0].getDocker
					&& ((shape.dockers[0].getDocker().getDockedShape() && !childShapeResourceIds
							.include(shape.dockers[0].getDocker()
									.getDockedShape().resourceId)) || !shape
							.getShape().dockers[0].getDockedShape()
							&& !outgoings[shape.resourceId])) {

				shape.sourceRemoved = true;
			}

			return shape;
		}.bind(this), true, true);

		// Iterate over top-level shapes
		canvas.eachChild(function(shape, parent) {
			// All top-level shapes should get an offset in their bounds
			// Move the shape occording to COPY_MOVE_OFFSET
			if (this.clipboard.useOffset) {
				shape.bounds = {
					lowerRight : {
						x : shape.bounds.lowerRight.x
								+ ORYX.CONFIG.COPY_MOVE_OFFSET,
						y : shape.bounds.lowerRight.y
								+ ORYX.CONFIG.COPY_MOVE_OFFSET
					},
					upperLeft : {
						x : shape.bounds.upperLeft.x
								+ ORYX.CONFIG.COPY_MOVE_OFFSET,
						y : shape.bounds.upperLeft.y
								+ ORYX.CONFIG.COPY_MOVE_OFFSET
					}
				};
			}
			// Only apply offset to shapes with a target
			if (shape.dockers) {
				shape.dockers = shape.dockers.map(function(docker, i) {
					// If shape had a target but the copied does not have anyone
					// anymore,
					// migrate the relative dockers to absolute ones.
					if ((shape.targetRemoved === true
							&& i == shape.dockers.length - 1 && docker.getDocker)
							|| (shape.sourceRemoved === true && i == 0 && docker.getDocker)) {

						docker = docker.getDocker().bounds.center();
					}

					// If it is the first docker and it has a docked shape,
					// just return the coordinates
					if ((i == 0 && docker.getDocker instanceof Function
							&& shape.sourceRemoved !== true && (docker
							.getDocker().getDockedShape() || ((outgoings[shape.resourceId] || []).length > 0 && (!(shape
							.getShape() instanceof ORYX.Core.Node) || outgoings[shape.resourceId][0]
							.getShape() instanceof ORYX.Core.Node))))
							|| (i == shape.dockers.length - 1
									&& docker.getDocker instanceof Function
									&& shape.targetRemoved !== true && (docker
									.getDocker().getDockedShape() || shape.target))) {

						return {
							x : docker.x,
							y : docker.y,
							getDocker : docker.getDocker
						}
					} else if (this.clipboard.useOffset) {
						return {
							x : docker.x + ORYX.CONFIG.COPY_MOVE_OFFSET,
							y : docker.y + ORYX.CONFIG.COPY_MOVE_OFFSET,
							getDocker : docker.getDocker
						};
					} else {
						return {
							x : docker.x,
							y : docker.y,
							getDocker : docker.getDocker
						};
					}
				}.bind(this));

			} else if (shape.getShape() instanceof ORYX.Core.Node
					&& shape.dockers
					&& shape.dockers.length > 0
					&& (!shape.dockers.first().getDocker
							|| shape.sourceRemoved === true || !(shape.dockers
							.first().getDocker().getDockedShape() || outgoings[shape.resourceId]))) {

				shape.dockers = shape.dockers.map(function(docker, i) {

					if ((shape.sourceRemoved === true && i == 0 && docker.getDocker)) {
						docker = docker.getDocker().bounds.center();
					}

					if (this.clipboard.useOffset) {
						return {
							x : docker.x + ORYX.CONFIG.COPY_MOVE_OFFSET,
							y : docker.y + ORYX.CONFIG.COPY_MOVE_OFFSET,
							getDocker : docker.getDocker
						};
					} else {
						return {
							x : docker.x,
							y : docker.y,
							getDocker : docker.getDocker
						};
					}
				}.bind(this));
			}

			return shape;
		}.bind(this), false, true);

		this.clipboard.useOffset = true;
		this.facade.importJSON(canvas);
	},

	/**
	 * Performs the delete operation. No more asking.
	 */
	editDelete : function() {
		var selection = this.facade.getSelection();

		var clipboard = new ORYX.Plugins.Edit.ClipBoard();
		clipboard.refresh(selection, this.getAllShapesToConsider(selection));

		var command = new ORYX.Plugins.Edit.DeleteCommand(clipboard,
				this.facade);

		this.facade.executeCommands([command]);
	}
});

ORYX.Plugins.Edit.ClipBoard = Clazz.extend({
			construct : function() {
				this.shapesAsJson = [];
				this.selection = [];
				this.SSnamespace = "";
				this.useOffset = true;
			},
			isOccupied : function() {
				return this.shapesAsJson.length > 0;
			},
			refresh : function(selection, shapes, namespace, useNoOffset) {
				this.selection = selection;
				this.SSnamespace = namespace;
				// Store outgoings, targets and parents to restore them later on
				this.outgoings = {};
				this.parents = {};
				this.targets = {};
				this.useOffset = useNoOffset !== true;

				this.shapesAsJson = shapes.map(function(shape) {
							var s = shape.toJSON();
							s.parent = {
								resourceId : shape.getParentShape().resourceId
							};
							s.parentIndex = shape.getParentShape()
									.getChildShapes().indexOf(shape)
							return s;
						});
			}
		});

ORYX.Plugins.Edit.DeleteCommand = ORYX.Core.Command.extend({
	construct : function(clipboard, facade) {
		this.clipboard = clipboard;
		this.shapesAsJson = clipboard.shapesAsJson;
		this.facade = facade;

		// Store dockers of deleted shapes to restore connections
		this.dockers = this.shapesAsJson.map(function(shapeAsJson) {
			var shape = shapeAsJson.getShape();
			var incomingDockers = shape.getIncomingShapes().map(function(s) {
						return s.getDockers().last();
					});
			var outgoingDockers = shape.getOutgoingShapes().map(function(s) {
						return s.getDockers().first();
					});
			var dockers = shape.getDockers().concat(incomingDockers,
					outgoingDockers).compact().map(function(docker) {
						return {
							object : docker,
							referencePoint : docker.referencePoint,
							dockedShape : docker.getDockedShape()
						};
					});
			return dockers;
		}).flatten();
	},
	execute : function() {
		this.shapesAsJson.each(function(shapeAsJson) {
					// Delete shape
					this.facade.deleteShape(shapeAsJson.getShape());
				}.bind(this));

		this.facade.setSelection([]);
		this.facade.getCanvas().update();
		this.facade.updateSelection();

	},
	rollback : function() {
		this.shapesAsJson.each(function(shapeAsJson) {
					var shape = shapeAsJson.getShape();
					var parent = this.facade
							.getCanvas()
							.getChildShapeByResourceId(shapeAsJson.parent.resourceId)
							|| this.facade.getCanvas();
					parent.add(shape, shape.parentIndex);
				}.bind(this));

		// reconnect shapes
		this.dockers.each(function(d) {
					d.object.setDockedShape(d.dockedShape);
					d.object.setReferencePoint(d.referencePoint);
				}.bind(this));

		this.facade.setSelection(this.selectedShapes);
		this.facade.getCanvas().update();
		this.facade.updateSelection();

	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * @namespace Oryx name space for plugins
 * @name ORYX.Plugins
 */
if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

/**
 * The view plugin offers all of zooming functionality accessible over the tool
 * bar. This are zoom in, zoom out, zoom to standard, zoom fit to model.
 * 
 * @class ORYX.Plugins.View
 * @extends Clazz
 * @param {Object}
 *            facade The editor facade for plugins.
 */
ORYX.Plugins.View = {
	/** @lends ORYX.Plugins.View.prototype */
	facade : undefined,

	construct : function(facade, ownPluginData) {
		this.facade = facade;
		// Standard Values
		this.zoomLevel = 1.0;
		this.maxFitToScreenLevel = 1.5;
		this.minZoomLevel = 0.1;
		this.maxZoomLevel = 2.5;
		this.diff = 5; // difference between canvas and view port, s.th. like
						// toolbar??

		// Read properties
		if (ownPluginData !== undefined && ownPluginData !== null) {
			ownPluginData.properties.each(function(property) {
				if (property.zoomLevel) {
					this.zoomLevel = Number(1.0);
				}
				if (property.maxFitToScreenLevel) {
					this.maxFitToScreenLevel = Number(property.maxFitToScreenLevel);
				}
				if (property.minZoomLevel) {
					this.minZoomLevel = Number(property.minZoomLevel);
				}
				if (property.maxZoomLevel) {
					this.maxZoomLevel = Number(property.maxZoomLevel);
				}
			}.bind(this));
		}

		/* Register zoom in */
		this.facade.offer({
					'name' : ORYX.I18N.View.zoomIn,
					'functionality' : this.zoom.bind(this, [1.0
									+ ORYX.CONFIG.ZOOM_OFFSET]),
					'group' : ORYX.I18N.View.group,
					'icon' : ORYX.PATH + "images/magnifier_zoom_in.png",
					'description' : ORYX.I18N.View.zoomInDesc,
					'index' : 1,
					'minShape' : 0,
					'maxShape' : 0,
					'isEnabled' : function() {
						return this.zoomLevel < this.maxZoomLevel
					}.bind(this)
				});

		/* Register zoom out */
		this.facade.offer({
					'name' : ORYX.I18N.View.zoomOut,
					'functionality' : this.zoom.bind(this, [1.0
									- ORYX.CONFIG.ZOOM_OFFSET]),
					'group' : ORYX.I18N.View.group,
					'icon' : ORYX.PATH + "images/magnifier_zoom_out.png",
					'description' : ORYX.I18N.View.zoomOutDesc,
					'index' : 2,
					'minShape' : 0,
					'maxShape' : 0,
					'isEnabled' : function() {
						return this._checkSize()
					}.bind(this)
				});

		/* Register zoom standard */
		this.facade.offer({
					'name' : ORYX.I18N.View.zoomStandard,
					'functionality' : this.setAFixZoomLevel.bind(this, 1),
					'group' : ORYX.I18N.View.group,
					'icon' : ORYX.PATH + "images/zoom_standard.png",
					'cls' : 'icon-large',
					'description' : ORYX.I18N.View.zoomStandardDesc,
					'index' : 3,
					'minShape' : 0,
					'maxShape' : 0,
					'isEnabled' : function() {
						return this.zoomLevel != 1
					}.bind(this)
				});

		/* Register zoom fit to model */
		this.facade.offer({
					'name' : ORYX.I18N.View.zoomFitToModel,
					'functionality' : this.zoomFitToModel.bind(this),
					'group' : ORYX.I18N.View.group,
					'icon' : ORYX.PATH + "images/image.png",
					'description' : ORYX.I18N.View.zoomFitToModelDesc,
					'index' : 4,
					'minShape' : 0,
					'maxShape' : 0
				});
	},

	/**
	 * It sets the zoom level to a fix value and call the zooming function.
	 * 
	 * @param {Number}
	 *            zoomLevel the zoom level
	 */
	setAFixZoomLevel : function(zoomLevel) {
		this.zoomLevel = zoomLevel;
		this._checkZoomLevelRange();
		this.zoom(1);
	},

	/**
	 * It does the actual zooming. It changes the viewable size of the canvas
	 * and all to its child elements.
	 * 
	 * @param {Number}
	 *            factor the factor to adjust the zoom level
	 */
	zoom : function(factor) {
		// TODO: Zoomen auf allen Objekten im SVG-DOM

		this.zoomLevel *= factor;
		var scrollNode = this.facade.getCanvas().getHTMLContainer().parentNode.parentNode;
		var canvas = this.facade.getCanvas();
		var newWidth = canvas.bounds.width() * this.zoomLevel;
		var newHeight = canvas.bounds.height() * this.zoomLevel;

		/* Set new top offset */
		var offsetTop = (canvas.node.parentNode.parentNode.parentNode.offsetHeight - newHeight)
				/ 2.0;
		offsetTop = offsetTop > 20 ? offsetTop - 20 : 0;
		canvas.node.parentNode.parentNode.style.marginTop = offsetTop + "px";
		offsetTop += 5;
		canvas.getHTMLContainer().style.top = offsetTop + "px";

		/* readjust scrollbar */
		var newScrollTop = scrollNode.scrollTop
				- Math
						.round((canvas.getHTMLContainer().parentNode
								.getHeight() - newHeight)
								/ 2) + this.diff;
		var newScrollLeft = scrollNode.scrollLeft
				- Math
						.round((canvas.getHTMLContainer().parentNode.getWidth() - newWidth)
								/ 2) + this.diff;

		/* Set new Zoom-Level */
		canvas.setSize({
					width : newWidth,
					height : newHeight
				}, true);

		/* Set Scale-Factor */
		canvas.node.setAttributeNS(null, "transform", "scale(" + this.zoomLevel
						+ ")");

		/* Refresh the Selection */
		this.facade.updateSelection();
		scrollNode.scrollTop = newScrollTop;
		scrollNode.scrollLeft = newScrollLeft;

		/* Update the zoom-level */
		canvas.zoomLevel = this.zoomLevel;
	},

	/**
	 * It calculates the zoom level to fit whole model into the visible area of
	 * the canvas. Than the model gets zoomed and the position of the scroll
	 * bars are adjusted.
	 * 
	 */
	zoomFitToModel : function() {

		/* Get the size of the visible area of the canvas */
		var scrollNode = this.facade.getCanvas().getHTMLContainer().parentNode.parentNode;
		var visibleHeight = scrollNode.getHeight() - 30;
		var visibleWidth = scrollNode.getWidth() - 30;

		var nodes = this.facade.getCanvas().getChildShapes();

		if (!nodes || nodes.length < 1) {
			return false;
		}

		/* Calculate size of canvas to fit the model */
		var bounds = nodes[0].absoluteBounds().clone();
		nodes.each(function(node) {
					bounds.include(node.absoluteBounds().clone());
				});

		/* Set new Zoom Level */
		var scaleFactorWidth = visibleWidth / bounds.width();
		var scaleFactorHeight = visibleHeight / bounds.height();

		/* Choose the smaller zoom level to fit the whole model */
		var zoomFactor = scaleFactorHeight < scaleFactorWidth
				? scaleFactorHeight
				: scaleFactorWidth;

		/* Test if maximum zoom is reached */
		if (zoomFactor > this.maxFitToScreenLevel) {
			zoomFactor = this.maxFitToScreenLevel
		}
		/* Do zooming */
		this.setAFixZoomLevel(zoomFactor);

		/* Set scroll bar position */
		scrollNode.scrollTop = Math
				.round(bounds.upperLeft().y * this.zoomLevel)
				- 5;
		scrollNode.scrollLeft = Math.round(bounds.upperLeft().x
				* this.zoomLevel)
				- 5;

	},

	/**
	 * It checks if the zoom level is less or equal to the level, which is
	 * required to schow the whole canvas.
	 * 
	 * @private
	 */
	_checkSize : function() {
		var canvasParent = this.facade.getCanvas().getHTMLContainer().parentNode;
		var minForCanvas = Math
				.min(	(canvasParent.parentNode.getWidth() / canvasParent
								.getWidth()), (canvasParent.parentNode
								.getHeight() / canvasParent.getHeight()));
		return 1.05 > minForCanvas;

	},
	/**
	 * It checks if the zoom level is included in the definined zoom level
	 * range.
	 * 
	 * @private
	 */
	_checkZoomLevelRange : function() {
		/*
		 * var
		 * canvasParent=this.facade.getCanvas().getHTMLContainer().parentNode;
		 * var maxForCanvas=
		 * Math.max((canvasParent.parentNode.getWidth()/canvasParent.getWidth()),(canvasParent.parentNode.getHeight()/canvasParent.getHeight()));
		 * if(this.zoomLevel > maxForCanvas) { this.zoomLevel = maxForCanvas; }
		 */
		if (this.zoomLevel < this.minZoomLevel) {
			this.zoomLevel = this.minZoomLevel;
		}

		if (this.zoomLevel > this.maxZoomLevel) {
			this.zoomLevel = this.maxZoomLevel;
		}
	}
};

ORYX.Plugins.View = Clazz.extend(ORYX.Plugins.View);
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
if (!Signavio) {
	var Signavio = {}
};
if (!Signavio.Core) {
	Signavio.Core = {}
};
Signavio.Core.Version = "1.0";
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!Signavio) {
	var Signavio = new Object();
}

if (!Signavio.Plugins) {
	Signavio.Plugins = new Object();
}

if (!Signavio.Plugins.Utils) {
	Signavio.Plugins.Utils = new Object();
}

if (!Signavio.Helper) {
	Signavio.Helper = new Object();
}

new function() {

	/**
	 * Provides an uniq id
	 * 
	 * @overwrite
	 * @return {String}
	 * 
	 */
	ORYX.Editor.provideId = function() {
		var res = [], hex = '0123456789ABCDEF';

		for (var i = 0; i < 36; i++)
			res[i] = Math.floor(Math.random() * 0x10);

		res[14] = 4;
		res[19] = (res[19] & 0x3) | 0x8;

		for (var i = 0; i < 36; i++)
			res[i] = hex[res[i]];

		res[8] = res[13] = res[18] = res[23] = '-';

		return "sid-" + res.join('');
	};

}();

/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins) {
	ORYX.Plugins = new Object();
}

/**
 * This plugin is responsible for displaying loading indicators and to prevent
 * the user from accidently unloading the page by, e.g., pressing the backspace
 * button and returning to the previous site in history.
 * 
 * @param {Object}
 *            facade The editor plugin facade to register enhancements with.
 */
ORYX.Plugins.Loading = {

	construct : function(facade) {

		this.facade = facade;

		// The parent Node
		this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml",
				this.facade.getCanvas().getHTMLContainer().parentNode, ['div',
						{
							'class' : 'LoadingIndicator'
						}, '']);

		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_ENABLE,
				this.enableLoading.bind(this));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_DISABLE,
				this.disableLoading.bind(this));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_STATUS,
				this.showStatus.bind(this));

		this.disableLoading();
	},

	enableLoading : function(options) {
		if (options.text)
			this.node.innerHTML = options.text + "...";
		else
			this.node.innerHTML = ORYX.I18N.Loading.waiting;
		this.node.removeClassName('StatusIndicator');
		this.node.addClassName('LoadingIndicator');
		this.node.style.display = "block";

		var pos = this.facade.getCanvas().rootNode.parentNode.parentNode.parentNode.parentNode;

		this.node.style.top = pos.offsetTop + 'px';
		this.node.style.left = pos.offsetLeft + 'px';

	},

	disableLoading : function() {
		this.node.style.display = "none";
	},

	showStatus : function(options) {
		if (options.text) {
			this.node.innerHTML = options.text;
			this.node.addClassName('StatusIndicator');
			this.node.removeClassName('LoadingIndicator');
			this.node.style.display = 'block';

			var pos = this.facade.getCanvas().rootNode.parentNode.parentNode.parentNode.parentNode;

			this.node.style.top = pos.offsetTop + 'px';
			this.node.style.left = pos.offsetLeft + 'px';

			var tout = options.timeout ? options.timeout : 2000;

			window.setTimeout((function() {

						this.disableLoading();

					}).bind(this), tout);
		}

	}
}

ORYX.Plugins.Loading = Clazz.extend(ORYX.Plugins.Loading);
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
if (!ORYX.Plugins) {
	ORYX.Plugins = new Object();
}

/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

/**
 * This plugin is responsible for resizing the canvas.
 * 
 * @param {Object}
 *            facade The editor plugin facade to register enhancements with.
 */
ORYX.Plugins.CanvasResize = Clazz.extend({

	construct : function(facade) {

		this.facade = facade;
		new ORYX.Plugins.CanvasResizeButton(this.facade.getCanvas(), "N",
				this.resize.bind(this));
		new ORYX.Plugins.CanvasResizeButton(this.facade.getCanvas(), "W",
				this.resize.bind(this));
		new ORYX.Plugins.CanvasResizeButton(this.facade.getCanvas(), "E",
				this.resize.bind(this));
		new ORYX.Plugins.CanvasResizeButton(this.facade.getCanvas(), "S",
				this.resize.bind(this));

		window.setTimeout(function() {
					jQuery(window).trigger('resize');
				});

	},

	resize : function(position, shrink) {

		resizeCanvas = function(position, extentionSize, facade) {
			var canvas = facade.getCanvas();
			var b = canvas.bounds;
			var scrollNode = facade.getCanvas().getHTMLContainer().parentNode.parentNode;

			if (position == "E" || position == "W") {
				canvas.setSize({
							width : (b.width() + extentionSize)
									* canvas.zoomLevel,
							height : (b.height()) * canvas.zoomLevel
						})

			} else if (position == "S" || position == "N") {
				canvas.setSize({
							width : (b.width()) * canvas.zoomLevel,
							height : (b.height() + extentionSize)
									* canvas.zoomLevel
						})
			}

			if (position == "N" || position == "W") {

				var move = position == "N" ? {
					x : 0,
					y : extentionSize
				} : {
					x : extentionSize,
					y : 0
				};

				// Move all children
				canvas.getChildNodes(false, function(shape) {
							shape.bounds.moveBy(move)
						})
				// Move all dockers, when the edge has at least one docked shape
				var edges = canvas.getChildEdges().findAll(function(edge) {
							return edge.getAllDockedShapes().length > 0
						})
				var dockers = edges.collect(function(edge) {
							return edge.dockers.findAll(function(docker) {
										return !docker.getDockedShape()
									})
						}).flatten();
				dockers.each(function(docker) {
							docker.bounds.moveBy(move)
						})
			} else if (position == "S") {
				scrollNode.scrollTop += extentionSize;
			} else if (position == "E") {
				scrollNode.scrollLeft += extentionSize;
			}

			jQuery(window).trigger('resize');

			canvas.update();
			facade.updateSelection();
		}

		var commandClass = ORYX.Core.Command.extend({
					construct : function(position, extentionSize, facade) {
						this.position = position;
						this.extentionSize = extentionSize;
						this.facade = facade;
					},
					execute : function() {
						resizeCanvas(this.position, this.extentionSize,
								this.facade);
					},
					rollback : function() {
						resizeCanvas(this.position, -this.extentionSize,
								this.facade);
					},
					update : function() {
					}
				});

		var extentionSize = ORYX.CONFIG.CANVAS_RESIZE_INTERVAL;
		if (shrink)
			extentionSize = -extentionSize;
		var command = new commandClass(position, extentionSize, this.facade);

		this.facade.executeCommands([command]);

	}

});

ORYX.Plugins.CanvasResizeButton = Clazz.extend({

	construct : function(canvas, position, callback) {
		this.canvas = canvas;
		var parentNode = canvas.getHTMLContainer().parentNode;

		window.myParent = parentNode;

		var actualScrollNode = jQuery('#canvasSection')[0];
		var scrollNode = actualScrollNode;
		var canvasNode = jQuery('#canvasSection').find(".ORYX_Editor")[0];
		var svgRootNode = canvasNode.children[0];

		var iconClass = 'glyphicon glyphicon-chevron-';
		var iconClassShrink = 'glyphicon glyphicon-chevron-';
		if (position == 'N') {
			iconClass += 'up';
			iconClassShrink += 'down';
		} else if (position == 'S') {
			iconClass += 'down';
			iconClassShrink += 'up';
		} else if (position == 'E') {
			iconClass += 'right';
			iconClassShrink += 'left';
		} else if (position == 'W') {
			iconClass += 'left';
			iconClassShrink += 'right';
		}

		// The buttons
		var idGrow = 'canvas-shrink-' + position;
		var idShrink = 'canvas-grow-' + position;

		var buttonGrow = ORYX.Editor.graft("http://www.w3.org/1999/xhtml",
				parentNode, ['div', {
					'class' : 'canvas_resize_indicator canvas_resize_indicator_grow'
							+ ' ' + position,
					'id' : idGrow,
					'title' : ORYX.I18N.RESIZE.tipGrow
							+ ORYX.I18N.RESIZE[position]
				}, ['i', {
							'class' : iconClass
						}]]);
		var buttonShrink = ORYX.Editor.graft("http://www.w3.org/1999/xhtml",
				parentNode, ['div', {
					'class' : 'canvas_resize_indicator canvas_resize_indicator_shrink'
							+ ' ' + position,
					'id' : idShrink,
					'title' : ORYX.I18N.RESIZE.tipGrow
							+ ORYX.I18N.RESIZE[position]
				}, ['i', {
							'class' : iconClassShrink
						}]]);
		// Defines a callback which gives back
		// a boolean if the current mouse event
		// is over the particular button area
		var offSetWidth = 60;
		var isOverOffset = function(event) {

			var isOverButton = event.target.id.indexOf("canvas-shrink") != -1
					|| event.target.id.indexOf("canvas-grow") != -1
					|| event.target.parentNode.id.indexOf("canvas-shrink") != -1
					|| event.target.parentNode.id.indexOf("canvas-grow") != -1;
			if (isOverButton) {
				if (event.target.id == idGrow || event.target.id == idShrink
						|| event.target.parentNode.id == idGrow
						|| event.target.parentNode.id == idShrink) {
					return true;
				} else {
					return false;
				}
			}

			if (event.target != parentNode && event.target != scrollNode
					&& event.target != scrollNode.firstChild
					&& event.target != svgRootNode
					&& event.target != scrollNode) {
				return false;
			}

			// if(inCanvas){offSetWidth=30}else{offSetWidth=30*2}
			// Safari work around
			var X = event.offsetX !== undefined ? event.offsetX : event.layerX;
			var Y = event.offsetY !== undefined ? event.offsetY : event.layerY;

			var canvasOffset = 0;
			if (canvasNode.clientWidth < actualScrollNode.clientWidth) {
				var widthDiff = actualScrollNode.clientWidth
						- canvasNode.clientWidth;
				canvasOffset = widthDiff / 2;
			}

			// Adjust to relative location to the actual viewport
			Y = Y - actualScrollNode.scrollTop;
			X = X - actualScrollNode.scrollLeft;

			if (position == "N") {
				return Y < offSetWidth;
			} else if (position == "W") {
				return X < offSetWidth + canvasOffset;
			} else if (position == "E") {
				return actualScrollNode.clientWidth - X < offSetWidth
						+ canvasOffset;
			} else if (position == "S") {
				return actualScrollNode.clientHeight - Y < offSetWidth;
			}

			return false;
		};

		var showButtons = (function() {
			buttonGrow.show();

			var w = canvas.bounds.width();
			var h = canvas.bounds.height();

			if (position == "N"
					&& (h - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_HEIGHT))
				buttonShrink.show();
			else if (position == "E"
					&& (w - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_WIDTH))
				buttonShrink.show();
			else if (position == "S"
					&& (h - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_HEIGHT))
				buttonShrink.show();
			else if (position == "W"
					&& (w - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_WIDTH))
				buttonShrink.show();
			else
				buttonShrink.hide();

		}).bind(this);

		var hideButtons = function() {
			buttonGrow.hide();
			buttonShrink.hide();
		};

		// If the mouse move is over the button area, show the button
		parentNode.parentNode.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE,
				function(event) {
					if (isOverOffset(event)) {
						showButtons();
					} else {
						hideButtons()
					}
				}, false);
		// If the mouse is over the button, show them
		buttonGrow.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER,
				function(event) {
					showButtons();
				}, true);
		buttonShrink.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, function(
						event) {
					showButtons();
				}, true);
		// If the mouse is out, hide the button
		// scrollNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT,
		// function(event){button.hide()}, true )
		parentNode.parentNode.addEventListener(ORYX.CONFIG.EVENT_MOUSEOUT,
				function(event) {
					hideButtons()
				}, true);
		// svgRootNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT,
		// function(event){ inCanvas = false } , true );

		// Hide the button initialy
		hideButtons();

		// Add the callbacks
		buttonGrow.addEventListener('click', function() {
					callback(position);
					showButtons();
				}, true);
		buttonShrink.addEventListener('click', function() {
					callback(position, true);
					showButtons();
				}, true);

	}

});

/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.RenameShapes = Clazz.extend({

	facade : undefined,

	construct : function(facade) {

		this.facade = facade;

		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_CANVAS_SCROLL,
				this.hideField.bind(this));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DBLCLICK,
				this.actOnDBLClick.bind(this));
		this.facade.offer({
					keyCodes : [{
								keyCode : 113, // F2-Key
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.renamePerF2.bind(this)
				});

		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN,
				this.hide.bind(this), true);
	},

	/**
	 * This method handles the "F2" key down event. The selected shape are
	 * looked up and the editing of title/name of it gets started.
	 */
	renamePerF2 : function() {
		var selectedShapes = this.facade.getSelection();
		this.actOnDBLClick(undefined, selectedShapes.first());
	},

	actOnDBLClick : function(evt, shape) {

		if (!(shape instanceof ORYX.Core.Shape)) {
			return;
		}

		// Destroys the old input, if there is one
		this.destroy();

		// Get all properties which where at least one ref to view is set
		var props = shape.getStencil().properties().findAll(function(item) {
			return (item.refToView() && item.refToView().length > 0 && item
					.directlyEditable());
		});
		// from these, get all properties where write access are and the type is
		// String or Expression
		props = props.findAll(function(item) {
			return !item.readonly()
					&& (item.type() == ORYX.CONFIG.TYPE_STRING
							|| item.type() == ORYX.CONFIG.TYPE_EXPRESSION || item
							.type() == ORYX.CONFIG.TYPE_DATASOURCE);
		});

		// Get all ref ids
		var allRefToViews = props.collect(function(prop) {
					return prop.refToView();
				}).flatten().compact();
		// Get all labels from the shape with the ref ids
		var labels = shape.getLabels().findAll(function(label) {
					return allRefToViews.any(function(toView) {
								return label.id.endsWith(toView);
							});
				});

		// If there are no referenced labels --> return
		if (labels.length == 0) {
			return;
		}

		// Define the nearest label
		var nearestLabel = labels.length <= 1 ? labels[0] : null;
		if (!nearestLabel) {
			nearestLabel = labels.find(function(label) {
						return label.node == evt.target
								|| label.node == evt.target.parentNode;
					});
			if (!nearestLabel) {

				var evtCoord = this.facade.eventCoordinates(evt);

				var additionalIEZoom = 1;
				if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
					var ua = navigator.userAgent;
					if (ua.indexOf('MSIE') >= 0) {
						// IE 10 and below
						var zoom = Math
								.round((screen.deviceXDPI / screen.logicalXDPI)
										* 100);
						if (zoom !== 100) {
							additionalIEZoom = zoom / 100
						}
					}
				}

				if (additionalIEZoom !== 1) {
					evtCoord.x = evtCoord.x / additionalIEZoom;
					evtCoord.y = evtCoord.y / additionalIEZoom;
				}

				evtCoord.y += $("editor-header").clientHeight
						- $("canvasSection").scrollTop - 5;
				if (KISBPM.HEADER_CONFIG.showAppTitle == false) {
					evtCoord.y += 61;
				}

				evtCoord.x -= $("canvasSection").scrollLeft;

				var trans = this.facade.getCanvas().rootNode.lastChild
						.getScreenCTM();
				evtCoord.x *= trans.a;
				evtCoord.y *= trans.d;

				var diff = labels.collect(function(label) {
							var center = this.getCenterPosition(label.node);
							var len = Math.sqrt(Math.pow(center.x - evtCoord.x,
									2)
									+ Math.pow(center.y - evtCoord.y, 2));
							return {
								diff : len,
								label : label
							};
						}.bind(this));

				diff.sort(function(a, b) {
							return a.diff > b.diff;
						});

				nearestLabel = diff[0].label;

			}
		}
		// Get the particular property for the label
		var prop = props.find(function(item) {
					return item.refToView().any(function(toView) {
								return nearestLabel.id == shape.id + toView;
							});
				});

		// Get the center position from the nearest label
		var width = Math.min(Math.max(100, shape.bounds.width()), 200);
		var center = this.getCenterPosition(nearestLabel.node, shape);
		center.x -= (width / 2);
		var propId = prop.prefix() + "-" + prop.id();
		var textInput = document.createElement("textarea");
		textInput.id = 'shapeTextInput';
		textInput.style.position = 'absolute';
		textInput.style.width = width + 'px';
		textInput.style.left = (center.x < 10) ? 10 : center.x + 'px';
		textInput.style.top = (center.y - 15) + 'px';
		textInput.className = 'x-form-textarea x-form-field x_form_text_set_absolute';
		textInput.value = shape.properties[propId];
		this.oldValueText = shape.properties[propId];
		document.getElementById('canvasSection').appendChild(textInput);
		this.shownTextField = textInput;

		// Value change listener needs to be defined now since we reference it
		// in the text field
		this.updateValueFunction = function(newValue, oldValue) {
			var currentEl = shape;
			var facade = this.facade;

			if (oldValue != newValue) {
				// Implement the specific command for property change
				var commandClass = ORYX.Core.Command.extend({
							construct : function() {
								this.el = currentEl;
								this.propId = propId;
								this.oldValue = oldValue;
								this.newValue = newValue;
								this.facade = facade;
							},
							execute : function() {
								this.el.setProperty(this.propId, this.newValue);
								// this.el.update();
								this.facade.setSelection([this.el]);
								this.facade.getCanvas().update();
								this.facade.updateSelection();
							},
							rollback : function() {
								this.el.setProperty(this.propId, this.oldValue);
								// this.el.update();
								this.facade.setSelection([this.el]);
								this.facade.getCanvas().update();
								this.facade.updateSelection();
							}
						});
				// Instantiated the class
				var command = new commandClass();

				// Execute the command
				this.facade.executeCommands([command]);
			}
		}.bind(this);

		jQuery("#shapeTextInput").focus();

		jQuery("#shapeTextInput").autogrow();

		// Disable the keydown in the editor (that when hitting the delete
		// button, the shapes not get deleted)
		this.facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN);

	},

	getCenterPosition : function(svgNode, shape) {

		if (!svgNode) {
			return {
				x : 0,
				y : 0
			};
		}

		var scale = this.facade.getCanvas().node.getScreenCTM();
		var absoluteXY = shape.bounds.upperLeft();

		var hasParent = true;
		var searchShape = shape;
		while (hasParent) {
			if (searchShape.getParentShape().getStencil().idWithoutNs() === 'BPMNDiagram') {
				hasParent = false;
			} else {
				var parentXY = searchShape.getParentShape().bounds.upperLeft();
				absoluteXY.x += parentXY.x;
				absoluteXY.y += parentXY.y;
				searchShape = searchShape.getParentShape();
			}
		}

		var center = shape.bounds.midPoint();
		center.x += absoluteXY.x + scale.e;
		center.y += absoluteXY.y + scale.f;

		center.x *= scale.a;
		center.y *= scale.d;

		var additionalIEZoom = 1;
		if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
			var ua = navigator.userAgent;
			if (ua.indexOf('MSIE') >= 0) {
				// IE 10 and below
				var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI)
						* 100);
				if (zoom !== 100) {
					additionalIEZoom = zoom / 100
				}
			}
		}

		if (additionalIEZoom === 1) {
			center.y = center.y - jQuery("#canvasSection").offset().top + 5;
			center.x -= jQuery("#canvasSection").offset().left;

		} else {
			var canvasOffsetLeft = jQuery("#canvasSection").offset().left;
			var canvasScrollLeft = jQuery("#canvasSection").scrollLeft();
			var canvasScrollTop = jQuery("#canvasSection").scrollTop();

			var offset = scale.e - (canvasOffsetLeft * additionalIEZoom);
			var additionaloffset = 0;
			if (offset > 10) {
				additionaloffset = (offset / additionalIEZoom) - offset;
			}
			center.y = center.y
					- (jQuery("#canvasSection").offset().top * additionalIEZoom)
					+ 5
					+ ((canvasScrollTop * additionalIEZoom) - canvasScrollTop);
			center.x = center.x
					- (canvasOffsetLeft * additionalIEZoom)
					+ additionaloffset
					+ ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft);
		}

		return center;
	},

	hide : function(e) {
		if (this.shownTextField && (!e || e.target !== this.shownTextField)) {
			var newValue = this.shownTextField.value;
			if (newValue !== this.oldValueText) {
				this.updateValueFunction(newValue, this.oldValueText);
			}
			this.destroy();
		}
	},

	hideField : function(e) {
		if (this.shownTextField) {
			this.destroy();
		}
	},

	destroy : function(e) {
		var textInputComp = jQuery("#shapeTextInput");
		if (textInputComp) {
			textInputComp.remove();
			delete this.shownTextField;

			this.facade.enableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
		}
	}
});
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

/**
 * Supports EPCs by offering a syntax check and export and import ability..
 * 
 * 
 */
ORYX.Plugins.ProcessLink = Clazz.extend({

	facade : undefined,

	/**
	 * Offers the plugin functionality:
	 * 
	 */
	construct : function(facade) {

		this.facade = facade;

		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_PROPERTY_CHANGED,
				this.propertyChanged.bind(this));

	},

	/**
	 * 
	 * @param {Object}
	 *            option
	 */
	propertyChanged : function(option, node) {

		if (option.name !== "oryx-refuri" || !node instanceof ORYX.Core.Node) {
			return
		}

		if (option.value && option.value.length > 0
				&& option.value != "undefined") {

			this.show(node, option.value);

		} else {

			this.hide(node);

		}

	},

	/**
	 * Shows the Link for a particular shape with a specific url
	 * 
	 * @param {Object}
	 *            shape
	 * @param {Object}
	 *            url
	 */
	show : function(shape, url) {

		// Generate the svg-representation of a link
		var link = ORYX.Editor.graft("http://www.w3.org/2000/svg", null, ['a',
				{
					'target' : '_blank'
				}, ['path', {
					"stroke-width" : 1.0,
					"stroke" : "#00DD00",
					"fill" : "#00AA00",
					"d" : "M3,3 l0,-2.5 l7.5,0 l0,-2.5 l7.5,4.5 l-7.5,3.5 l0,-2.5 l-8,0",
					"line-captions" : "round"
				}]]);

		var link = ORYX.Editor.graft("http://www.w3.org/2000/svg", null, ['a',
				{
					'target' : '_blank'
				}, ['path', {
					"style" : "fill:#92BFFC;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72",
					"d" : "M0 1.44 L0 15.05 L11.91 15.05 L11.91 5.98 L7.37 1.44 L0 1.44 Z"
				}], ['path', {
					"style" : "stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72;fill:none;",
					"transform" : "translate(7.5, -8.5)",
					"d" : "M0 10.51 L0 15.05 L4.54 15.05"
				}], ['path', {
					"style" : "fill:#f28226;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72",
					"transform" : "translate(-3, -1)",
					"d" : "M0 8.81 L0 13.06 L5.95 13.06 L5.95 15.05 A50.2313 50.2313 -175.57 0 0 10.77 11.08 A49.9128 49.9128 -1.28 0 0 5.95 6.54 L5.95 8.81 L0 8.81 Z"
				}],]);

		/*
		 *  [ 'a', {'target': '_blank'}, ['path', { "style":
		 * "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M7,4 l0,2"}],
		 * ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000",
		 * "d": "M4,8 l-2,0 l0,6"}], ['path', { "style":
		 * "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M10,8 l2,0
		 * l0,6"}], ['rect', { "style":
		 * "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height":
		 * 4, "x": 4, "y": 0}], ['rect', { "style":
		 * "fill:#ffafff;stroke:#000000;stroke-width:1", "width": 6, "height":
		 * 4, "x": 4, "y": 6}], ['rect', { "style":
		 * "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height":
		 * 4, "x": 0, "y": 12}], ['rect', { "style":
		 * "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height":
		 * 4, "x": 8, "y": 12}], ['rect', { "style":
		 * "fill:none;stroke:none;pointer-events:all", "width": 14, "height":
		 * 16, "x": 0, "y": 0}] ]);
		 */

		// Set the link with the special namespace
		link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", url);

		// Shows the link in the overlay
		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_OVERLAY_SHOW,
					id : "arissupport.urlref_" + shape.id,
					shapes : [shape],
					node : link,
					nodePosition : "SE"
				});

	},

	/**
	 * Hides the Link for a particular shape
	 * 
	 * @param {Object}
	 *            shape
	 */
	hide : function(shape) {

		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_OVERLAY_HIDE,
					id : "arissupport.urlref_" + shape.id
				});

	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

Array.prototype.insertFrom = function(from, to) {
	to = Math.max(0, to);
	from = Math.min(Math.max(0, from), this.length - 1);

	var el = this[from];
	var old = this.without(el);
	var newA = old.slice(0, to);
	newA.push(el);
	if (old.length > to) {
		newA = newA.concat(old.slice(to))
	};
	return newA;
}

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.Arrangement = ORYX.Plugins.AbstractPlugin.extend({

	facade : undefined,

	construct : function(facade) {
		this.facade = facade;

		// Z-Ordering
		/**
		 * Hide for SIGNAVIO
		 * 
		 * this.facade.offer({ 'name':ORYX.I18N.Arrangement.btf,
		 * 'functionality': this.setZLevel.bind(this, this.setToTop), 'group':
		 * ORYX.I18N.Arrangement.groupZ, 'icon': ORYX.PATH +
		 * "images/shape_move_front.png", 'description':
		 * ORYX.I18N.Arrangement.btfDesc, 'index': 1, 'minShape': 1});
		 * 
		 * this.facade.offer({ 'name':ORYX.I18N.Arrangement.btb,
		 * 'functionality': this.setZLevel.bind(this, this.setToBack), 'group':
		 * ORYX.I18N.Arrangement.groupZ, 'icon': ORYX.PATH +
		 * "images/shape_move_back.png", 'description':
		 * ORYX.I18N.Arrangement.btbDesc, 'index': 2, 'minShape': 1});
		 * 
		 * this.facade.offer({ 'name':ORYX.I18N.Arrangement.bf, 'functionality':
		 * this.setZLevel.bind(this, this.setForward), 'group':
		 * ORYX.I18N.Arrangement.groupZ, 'icon': ORYX.PATH +
		 * "images/shape_move_forwards.png", 'description':
		 * ORYX.I18N.Arrangement.bfDesc, 'index': 3, 'minShape': 1});
		 * 
		 * this.facade.offer({ 'name':ORYX.I18N.Arrangement.bb, 'functionality':
		 * this.setZLevel.bind(this, this.setBackward), 'group':
		 * ORYX.I18N.Arrangement.groupZ, 'icon': ORYX.PATH +
		 * "images/shape_move_backwards.png", 'description':
		 * ORYX.I18N.Arrangement.bbDesc, 'index': 4, 'minShape': 1});
		 *  // Aligment this.facade.offer({ 'name':ORYX.I18N.Arrangement.ab,
		 * 'functionality': this.alignShapes.bind(this,
		 * [ORYX.CONFIG.EDITOR_ALIGN_BOTTOM]), 'group':
		 * ORYX.I18N.Arrangement.groupA, 'icon': ORYX.PATH +
		 * "images/shape_align_bottom.png", 'description':
		 * ORYX.I18N.Arrangement.abDesc, 'index': 1, 'minShape': 2});
		 * 
		 * 
		 * 
		 * this.facade.offer({ 'name':ORYX.I18N.Arrangement.at, 'functionality':
		 * this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_TOP]), 'group':
		 * ORYX.I18N.Arrangement.groupA, 'icon': ORYX.PATH +
		 * "images/shape_align_top.png", 'description':
		 * ORYX.I18N.Arrangement.atDesc, 'index': 3, 'minShape': 2});
		 * 
		 * this.facade.offer({ 'name':ORYX.I18N.Arrangement.al, 'functionality':
		 * this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_LEFT]),
		 * 'group': ORYX.I18N.Arrangement.groupA, 'icon': ORYX.PATH +
		 * "images/shape_align_left.png", 'description':
		 * ORYX.I18N.Arrangement.alDesc, 'index': 4, 'minShape': 2});
		 * 
		 * this.facade.offer({ 'name':ORYX.I18N.Arrangement.ar, 'functionality':
		 * this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_RIGHT]),
		 * 'group': ORYX.I18N.Arrangement.groupA, 'icon': ORYX.PATH +
		 * "images/shape_align_right.png", 'description':
		 * ORYX.I18N.Arrangement.arDesc, 'index': 6, 'minShape': 2});
		 * 
		 */

		this.facade.offer({
					'name' : ORYX.I18N.Arrangement.am,
					'functionality' : this.alignShapes.bind(this,
							[ORYX.CONFIG.EDITOR_ALIGN_MIDDLE]),
					'group' : ORYX.I18N.Arrangement.groupA,
					'icon' : ORYX.PATH + "images/shape_align_middle.png",
					'description' : ORYX.I18N.Arrangement.amDesc,
					'index' : 1,
					'minShape' : 2
				});

		this.facade.offer({
					'name' : ORYX.I18N.Arrangement.ac,
					'functionality' : this.alignShapes.bind(this,
							[ORYX.CONFIG.EDITOR_ALIGN_CENTER]),
					'group' : ORYX.I18N.Arrangement.groupA,
					'icon' : ORYX.PATH + "images/shape_align_center.png",
					'description' : ORYX.I18N.Arrangement.acDesc,
					'index' : 2,
					'minShape' : 2
				});

		this.facade.offer({
					'name' : ORYX.I18N.Arrangement.as,
					'functionality' : this.alignShapes.bind(this,
							[ORYX.CONFIG.EDITOR_ALIGN_SIZE]),
					'group' : ORYX.I18N.Arrangement.groupA,
					'icon' : ORYX.PATH + "images/shape_align_size.png",
					'description' : ORYX.I18N.Arrangement.asDesc,
					'index' : 3,
					'minShape' : 2
				});

		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_TOP,
				this.setZLevel.bind(this, this.setToTop));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_BACK,
				this.setZLevel.bind(this, this.setToBack));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD,
				this.setZLevel.bind(this, this.setForward));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD,
				this.setZLevel.bind(this, this.setBackward));

	},

	onSelectionChanged : function(elemnt) {
		var selection = this.facade.getSelection();
		if (selection.length === 1 && selection[0] instanceof ORYX.Core.Edge) {
			this.setToTop(selection);
		}
	},

	setZLevel : function(callback, event) {

		// Command-Pattern for dragging one docker
		var zLevelCommand = ORYX.Core.Command.extend({
			construct : function(callback, elements, facade) {
				this.callback = callback;
				this.elements = elements;
				// For redo, the previous elements get stored
				this.elAndIndex = elements.map(function(el) {
							return {
								el : el,
								previous : el.parent.children[el.parent.children
										.indexOf(el)
										- 1]
							}
						})
				this.facade = facade;
			},
			execute : function() {

				// Call the defined z-order callback with the elements
				this.callback(this.elements)
				this.facade.setSelection(this.elements)
			},
			rollback : function() {

				// Sort all elements on the index of there containment
				var sortedEl = this.elAndIndex.sortBy(function(el) {
							var value = el.el;
							var t = $A(value.node.parentNode.childNodes);
							return t.indexOf(value.node);
						});

				// Every element get setted back bevor the old previous element
				for (var i = 0; i < sortedEl.length; i++) {
					var el = sortedEl[i].el;
					var p = el.parent;
					var oldIndex = p.children.indexOf(el);
					var newIndex = p.children.indexOf(sortedEl[i].previous);
					newIndex = newIndex || 0
					p.children = p.children.insertFrom(oldIndex, newIndex)
					el.node.parentNode.insertBefore(el.node,
							el.node.parentNode.childNodes[newIndex + 1]);
				}

				// Reset the selection
				this.facade.setSelection(this.elements)
			}
		});

		// Instanziate the dockCommand
		var command = new zLevelCommand(callback, this.facade.getSelection(),
				this.facade);
		if (event.excludeCommand) {
			command.execute();
		} else {
			this.facade.executeCommands([command]);
		}

	},

	setToTop : function(elements) {

		// Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem
		// Elternknoten.
		var tmpElem = elements.sortBy(function(value, index) {
					var t = $A(value.node.parentNode.childNodes);
					return t.indexOf(value.node);
				});
		// Sortiertes Array wird nach oben verschoben.
		tmpElem.each(function(value) {
					var p = value.parent;
					if (p.children.last() === value) {
						return;
					}
					p.children = p.children.without(value)
					p.children.push(value);
					value.node.parentNode.appendChild(value.node);
				});
	},

	setToBack : function(elements) {
		// Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem
		// Elternknoten.
		var tmpElem = elements.sortBy(function(value, index) {
					var t = $A(value.node.parentNode.childNodes);
					return t.indexOf(value.node);
				});

		tmpElem = tmpElem.reverse();

		// Sortiertes Array wird nach unten verschoben.
		tmpElem.each(function(value) {
					var p = value.parent
					p.children = p.children.without(value)
					p.children.unshift(value);
					value.node.parentNode.insertBefore(value.node,
							value.node.parentNode.firstChild);
				});

	},

	setBackward : function(elements) {
		// Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem
		// Elternknoten.
		var tmpElem = elements.sortBy(function(value, index) {
					var t = $A(value.node.parentNode.childNodes);
					return t.indexOf(value.node);
				});

		// Reverse the elements
		tmpElem = tmpElem.reverse();

		// Delete all Nodes who are the next Node in the nodes-Array
		var compactElem = tmpElem.findAll(function(el) {
					return !tmpElem.some(function(checkedEl) {
								return checkedEl.node == el.node.previousSibling
							})
				});

		// Sortiertes Array wird nach eine Ebene nach oben verschoben.
		compactElem.each(function(el) {
					if (el.node.previousSibling === null) {
						return;
					}
					var p = el.parent;
					var index = p.children.indexOf(el);
					p.children = p.children.insertFrom(index, index - 1)
					el.node.parentNode.insertBefore(el.node,
							el.node.previousSibling);
				});

	},

	setForward : function(elements) {
		// Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem
		// Elternknoten.
		var tmpElem = elements.sortBy(function(value, index) {
					var t = $A(value.node.parentNode.childNodes);
					return t.indexOf(value.node);
				});

		// Delete all Nodes who are the next Node in the nodes-Array
		var compactElem = tmpElem.findAll(function(el) {
					return !tmpElem.some(function(checkedEl) {
								return checkedEl.node == el.node.nextSibling
							})
				});

		// Sortiertes Array wird eine Ebene nach unten verschoben.
		compactElem.each(function(el) {
					var nextNode = el.node.nextSibling
					if (nextNode === null) {
						return;
					}
					var index = el.parent.children.indexOf(el);
					var p = el.parent;
					p.children = p.children.insertFrom(index, index + 1)
					el.node.parentNode.insertBefore(nextNode, el.node);
				});
	},

	alignShapes : function(way) {

		var elements = this.facade.getSelection();

		// Set the elements to all Top-Level elements
		elements = this.facade.getCanvas().getShapesWithSharedParent(elements);
		// Get only nodes
		elements = elements.findAll(function(value) {
					return (value instanceof ORYX.Core.Node)
				});
		// Delete all attached intermediate events from the array
		elements = elements.findAll(function(value) {
					var d = value.getIncomingShapes()
					return d.length == 0 || !elements.include(d[0])
				});
		if (elements.length < 2) {
			return;
		}

		// get bounds of all shapes.
		var bounds = elements[0].absoluteBounds().clone();
		elements.each(function(shape) {
					bounds.include(shape.absoluteBounds().clone());
				});

		// get biggest width and heigth
		var maxWidth = 0;
		var maxHeight = 0;
		elements.each(function(shape) {
					maxWidth = Math.max(shape.bounds.width(), maxWidth);
					maxHeight = Math.max(shape.bounds.height(), maxHeight);
				});

		var commandClass = ORYX.Core.Command.extend({
			construct : function(elements, bounds, maxHeight, maxWidth, way,
					plugin) {
				this.elements = elements;
				this.bounds = bounds;
				this.maxHeight = maxHeight;
				this.maxWidth = maxWidth;
				this.way = way;
				this.facade = plugin.facade;
				this.plugin = plugin;
				this.orgPos = [];
			},
			setBounds : function(shape, maxSize) {
				if (!maxSize)
					maxSize = {
						width : ORYX.CONFIG.MAXIMUM_SIZE,
						height : ORYX.CONFIG.MAXIMUM_SIZE
					};

				if (!shape.bounds) {
					throw "Bounds not definined."
				}

				var newBounds = {
					a : {
						x : shape.bounds.upperLeft().x
								- (this.maxWidth - shape.bounds.width()) / 2,
						y : shape.bounds.upperLeft().y
								- (this.maxHeight - shape.bounds.height()) / 2
					},
					b : {
						x : shape.bounds.lowerRight().x
								+ (this.maxWidth - shape.bounds.width()) / 2,
						y : shape.bounds.lowerRight().y
								+ (this.maxHeight - shape.bounds.height()) / 2
					}
				}

				/*
				 * If the new width of shape exceeds the maximum width, set
				 * width value to maximum.
				 */
				if (this.maxWidth > maxSize.width) {
					newBounds.a.x = shape.bounds.upperLeft().x
							- (maxSize.width - shape.bounds.width()) / 2;

					newBounds.b.x = shape.bounds.lowerRight().x
							+ (maxSize.width - shape.bounds.width()) / 2
				}

				/*
				 * If the new height of shape exceeds the maximum height, set
				 * height value to maximum.
				 */
				if (this.maxHeight > maxSize.height) {
					newBounds.a.y = shape.bounds.upperLeft().y
							- (maxSize.height - shape.bounds.height()) / 2;

					newBounds.b.y = shape.bounds.lowerRight().y
							+ (maxSize.height - shape.bounds.height()) / 2
				}

				/* set bounds of shape */
				shape.bounds.set(newBounds);

			},
			execute : function() {
				// align each shape according to the way that was specified.
				this.elements.each(function(shape, index) {
					this.orgPos[index] = shape.bounds.upperLeft();

					var relBounds = this.bounds.clone();
					var newCoordinates;
					if (shape.parent
							&& !(shape.parent instanceof ORYX.Core.Canvas)) {
						var upL = shape.parent.absoluteBounds().upperLeft();
						relBounds.moveBy(-upL.x, -upL.y);
					}

					switch (this.way) {
						// align the shapes in the requested way.
						case ORYX.CONFIG.EDITOR_ALIGN_BOTTOM :
							newCoordinates = {
								x : shape.bounds.upperLeft().x,
								y : relBounds.b.y - shape.bounds.height()
							};
							break;

						case ORYX.CONFIG.EDITOR_ALIGN_MIDDLE :
							newCoordinates = {
								x : shape.bounds.upperLeft().x,
								y : (relBounds.a.y + relBounds.b.y - shape.bounds
										.height())
										/ 2
							};
							break;

						case ORYX.CONFIG.EDITOR_ALIGN_TOP :
							newCoordinates = {
								x : shape.bounds.upperLeft().x,
								y : relBounds.a.y
							};
							break;

						case ORYX.CONFIG.EDITOR_ALIGN_LEFT :
							newCoordinates = {
								x : relBounds.a.x,
								y : shape.bounds.upperLeft().y
							};
							break;

						case ORYX.CONFIG.EDITOR_ALIGN_CENTER :
							newCoordinates = {
								x : (relBounds.a.x + relBounds.b.x - shape.bounds
										.width())
										/ 2,
								y : shape.bounds.upperLeft().y
							};
							break;

						case ORYX.CONFIG.EDITOR_ALIGN_RIGHT :
							newCoordinates = {
								x : relBounds.b.x - shape.bounds.width(),
								y : shape.bounds.upperLeft().y
							};
							break;

						case ORYX.CONFIG.EDITOR_ALIGN_SIZE :
							if (shape.isResizable) {
								this.orgPos[index] = {
									a : shape.bounds.upperLeft(),
									b : shape.bounds.lowerRight()
								};
								this.setBounds(shape, shape.maximumSize);
							}
							break;
					}

					if (newCoordinates) {
						var offset = {
							x : shape.bounds.upperLeft().x - newCoordinates.x,
							y : shape.bounds.upperLeft().y - newCoordinates.y
						}
						// Set the new position
						shape.bounds.moveTo(newCoordinates);
						this.plugin.layoutEdges(shape, shape
										.getAllDockedShapes(), offset);
						// shape.update()
					}
				}.bind(this));

				// this.facade.getCanvas().update();
				// this.facade.updateSelection();
			},
			rollback : function() {
				this.elements.each(function(shape, index) {
							if (this.way == ORYX.CONFIG.EDITOR_ALIGN_SIZE) {
								if (shape.isResizable) {
									shape.bounds.set(this.orgPos[index]);
								}
							} else {
								shape.bounds.moveTo(this.orgPos[index]);
							}
						}.bind(this));

				// this.facade.getCanvas().update();
				// this.facade.updateSelection();
			}
		})

		var command = new commandClass(elements, bounds, maxHeight, maxWidth,
				parseInt(way), this);

		this.facade.executeCommands([command]);
	}
});/*
	 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
	 * rights for this program may be obtained from Alfresco Software, Ltd.
	 * pursuant to a written agreement and any use of this program without such
	 * an agreement is prohibited.
	 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.Save = Clazz.extend({

	facade : undefined,

	processURI : undefined,

	changeSymbol : "*",

	construct : function(facade) {
		this.facade = facade;

		document.addEventListener("keydown", function(e) {
					if (e.ctrlKey && e.keyCode === 83) {
						Event.stop(e);
					}
				}, false);

		window.onbeforeunload = this.onUnLoad.bind(this);

		this.changeDifference = 0;

		// Register on event for executing commands --> store all commands in a
		// stack
		// --> Execute
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_EXECUTE, function() {
					this.changeDifference++;
					this.updateTitle();
				}.bind(this));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_EXECUTE_COMMANDS,
				function() {
					this.changeDifference++;
					this.updateTitle();
				}.bind(this));
		// --> Saved from other places in the editor
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SAVED, function() {
					this.changeDifference = 0;
					this.updateTitle();
				}.bind(this));

		// --> Rollback
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_ROLLBACK,
				function() {
					this.changeDifference--;
					this.updateTitle();
				}.bind(this));

		// TODO very critical for load time performance!!!
		// this.serializedDOM = DataManager.__persistDOM(this.facade);

		this.hasChanges = this._hasChanges.bind(this);
	},

	updateTitle : function() {

		var value = window.document.title
				|| document.getElementsByTagName("title")[0].childNodes[0].nodeValue;

		if (this.changeDifference === 0 && value.startsWith(this.changeSymbol)) {
			window.document.title = value.slice(1);
		} else if (this.changeDifference !== 0
				&& !value.startsWith(this.changeSymbol)) {
			window.document.title = this.changeSymbol + "" + value;
		}
	},

	_hasChanges : function() {
		return this.changeDifference !== 0
				|| (this.facade.getModelMetaData()['new'] && this.facade
						.getCanvas().getChildShapes().size() > 0);
	},

	onUnLoad : function() {
		if (this._hasChanges()) {
			return ORYX.I18N.Save.unsavedData;
		}
	}
});
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.DragDropResize = ORYX.Plugins.AbstractPlugin.extend({

	/**
	 * Constructor
	 * 
	 * @param {Object}
	 *            Facade: The Facade of the Editor
	 */
	construct : function(facade) {
		this.facade = facade;

		// Initialize variables
		this.currentShapes = []; // Current selected Shapes
		// this.pluginsData = []; // Available Plugins
		this.toMoveShapes = []; // Shapes there will be moved
		this.distPoints = []; // Distance Points for Snap on Grid
		this.isResizing = false; // Flag: If there was currently resized
		this.dragEnable = false; // Flag: If Dragging is enabled
		this.dragIntialized = false; // Flag: If the Dragging is initialized
		this.edgesMovable = true; // Flag: If an edge is docked it is not
									// movable
		this.offSetPosition = {
			x : 0,
			y : 0
		}; // Offset of the Dragging
		this.faktorXY = {
			x : 1,
			y : 1
		}; // The Current Zoom-Faktor
		this.containmentParentNode; // the current future parent node for the
									// dragged shapes
		this.isAddingAllowed = false; // flag, if adding current selected
										// shapes to containmentParentNode is
										// allowed
		this.isAttachingAllowed = false; // flag, if attaching to the current
											// shape is allowed

		this.callbackMouseMove = this.handleMouseMove.bind(this);
		this.callbackMouseUp = this.handleMouseUp.bind(this);

		// Get the SVG-Containernode
		var containerNode = this.facade.getCanvas().getSvgContainer();

		// Create the Selected Rectangle in the SVG
		this.selectedRect = new ORYX.Plugins.SelectedRect(containerNode);

		// Show grid line if enabled
		if (ORYX.CONFIG.SHOW_GRIDLINE) {
			this.vLine = new ORYX.Plugins.GridLine(containerNode,
					ORYX.Plugins.GridLine.DIR_VERTICAL);
			this.hLine = new ORYX.Plugins.GridLine(containerNode,
					ORYX.Plugins.GridLine.DIR_HORIZONTAL);
		}

		// Get a HTML-ContainerNode
		containerNode = this.facade.getCanvas().getHTMLContainer();

		this.scrollNode = this.facade.getCanvas().rootNode.parentNode.parentNode;

		// Create the southeastern button for resizing
		this.resizerSE = new ORYX.Plugins.Resizer(containerNode, "southeast",
				this.facade);
		this.resizerSE.registerOnResize(this.onResize.bind(this)); // register
																	// the
																	// resize
																	// callback
		this.resizerSE.registerOnResizeEnd(this.onResizeEnd.bind(this)); // register
																			// the
																			// resize
																			// end
																			// callback
		this.resizerSE.registerOnResizeStart(this.onResizeStart.bind(this)); // register
																				// the
																				// resize
																				// start
																				// callback

		// Create the northwestern button for resizing
		this.resizerNW = new ORYX.Plugins.Resizer(containerNode, "northwest",
				this.facade);
		this.resizerNW.registerOnResize(this.onResize.bind(this)); // register
																	// the
																	// resize
																	// callback
		this.resizerNW.registerOnResizeEnd(this.onResizeEnd.bind(this)); // register
																			// the
																			// resize
																			// end
																			// callback
		this.resizerNW.registerOnResizeStart(this.onResizeStart.bind(this)); // register
																				// the
																				// resize
																				// start
																				// callback

		// For the Drag and Drop
		// Register on MouseDown-Event on a Shape
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN,
				this.handleMouseDown.bind(this));
	},

	/**
	 * On Mouse Down
	 * 
	 */
	handleMouseDown : function(event, uiObj) {
		// If the selection Bounds not intialized and the uiObj is not member of
		// current selectio
		// then return
		if (!this.dragBounds || !this.currentShapes.member(uiObj)
				|| !this.toMoveShapes.length) {
			return;
		};

		// Start Dragging
		this.dragEnable = true;
		this.dragIntialized = true;
		this.edgesMovable = true;

		// Calculate the current zoom factor
		var a = this.facade.getCanvas().node.getScreenCTM();
		this.faktorXY.x = a.a;
		this.faktorXY.y = a.d;

		var eventX = Event.pointerX(event);
		var eventY = Event.pointerY(event);

		// Set the offset position of dragging
		var upL = this.dragBounds.upperLeft();
		this.offSetPosition = {
			x : eventX - (upL.x * this.faktorXY.x),
			y : eventY - (upL.y * this.faktorXY.y)
		};

		this.offsetScroll = {
			x : this.scrollNode.scrollLeft,
			y : this.scrollNode.scrollTop
		};

		// Register on Global Mouse-MOVE Event
		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE,
				this.callbackMouseMove, false);
		// Register on Global Mouse-UP Event
		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP,
				this.callbackMouseUp, true);

		return;
	},

	/**
	 * On Key Mouse Up
	 * 
	 */
	handleMouseUp : function(event) {

		// disable containment highlighting
		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
					highlightId : "dragdropresize.contain"
				});

		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
					highlightId : "dragdropresize.attached"
				});

		// If Dragging is finished
		if (this.dragEnable) {

			// and update the current selection
			if (!this.dragIntialized) {

				// Do Method after Dragging
				this.afterDrag();

				// Check if the Shape is allowed to dock to the other Shape
				if (this.isAttachingAllowed && this.toMoveShapes.length == 1
						&& this.toMoveShapes[0] instanceof ORYX.Core.Node
						&& this.toMoveShapes[0].dockers.length > 0) {

					// Get the position and the docker
					var position = this.facade.eventCoordinates(event);
					var docker = this.toMoveShapes[0].dockers[0];

					// Command-Pattern for dragging several Shapes
					var dockCommand = ORYX.Core.Command.extend({
						construct : function(docker, position, newDockedShape,
								facade) {
							this.docker = docker;
							this.newPosition = position;
							this.newDockedShape = newDockedShape;
							this.newParent = newDockedShape.parent
									|| facade.getCanvas();
							this.oldPosition = docker.parent.bounds.center();
							this.oldDockedShape = docker.getDockedShape();
							this.oldParent = docker.parent.parent
									|| facade.getCanvas();
							this.facade = facade;

							if (this.oldDockedShape) {
								this.oldPosition = docker.parent
										.absoluteBounds().center();
							}

						},
						execute : function() {
							this.dock(this.newDockedShape, this.newParent,
									this.newPosition);

							// Raise Event for having the docked shape on top of
							// the other shape
							this.facade.raiseEvent({
										type : ORYX.CONFIG.EVENT_ARRANGEMENT_TOP,
										excludeCommand : true
									})
						},
						rollback : function() {
							this.dock(this.oldDockedShape, this.oldParent,
									this.oldPosition);
						},
						dock : function(toDockShape, parent, pos) {
							// Add to the same parent Shape
							parent.add(this.docker.parent)

							// Set the Docker to the new Shape
							this.docker.setDockedShape(undefined);
							this.docker.bounds.centerMoveTo(pos)
							this.docker.setDockedShape(toDockShape);
							// this.docker.update();

							this.facade.setSelection([this.docker.parent]);
							this.facade.getCanvas().update();
							this.facade.updateSelection();

						}
					});

					// Instanziate the dockCommand
					var commands = [new dockCommand(docker, position,
							this.containmentParentNode, this.facade)];
					this.facade.executeCommands(commands);

					// Check if adding is allowed to the other Shape
				} else if (this.isAddingAllowed) {

					// Refresh all Shapes --> Set the new Bounds
					this.refreshSelectedShapes();

				}

				this.facade.updateSelection();

				// this.currentShapes.each(function(shape) {shape.update()})
				// Raise Event: Dragging is finished
				this.facade.raiseEvent({
							type : ORYX.CONFIG.EVENT_DRAGDROP_END
						});
			}

			if (this.vLine)
				this.vLine.hide();
			if (this.hLine)
				this.hLine.hide();
		}

		// Disable
		this.dragEnable = false;

		// UnRegister on Global Mouse-UP/-Move Event
		document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEUP,
				this.callbackMouseUp, true);
		document.documentElement.removeEventListener(
				ORYX.CONFIG.EVENT_MOUSEMOVE, this.callbackMouseMove, false);

		return;
	},

	/**
	 * On Key Mouse Move
	 * 
	 */
	handleMouseMove : function(event) {
		// If dragging is not enabled, go return
		if (!this.dragEnable) {
			return
		};
		// If Dragging is initialized
		if (this.dragIntialized) {
			// Raise Event: Drag will be started
			this.facade.raiseEvent({
						type : ORYX.CONFIG.EVENT_DRAGDROP_START
					});
			this.dragIntialized = false;

			// And hide the resizers and the highlighting
			this.resizerSE.hide();
			this.resizerNW.hide();

			// if only edges are selected, containmentParentNode must be the
			// canvas
			this._onlyEdges = this.currentShapes.all(function(currentShape) {
						return (currentShape instanceof ORYX.Core.Edge);
					});

			// Do method before Drag
			this.beforeDrag();

			this._currentUnderlyingNodes = [];

		}

		// Calculate the new position
		var position = {
			x : Event.pointerX(event) - this.offSetPosition.x,
			y : Event.pointerY(event) - this.offSetPosition.y
		}

		position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft;
		position.y -= this.offsetScroll.y - this.scrollNode.scrollTop;

		// If not the Control-Key are pressed
		var modifierKeyPressed = event.shiftKey || event.ctrlKey;
		if (ORYX.CONFIG.GRID_ENABLED && !modifierKeyPressed) {
			// Snap the current position to the nearest Snap-Point
			position = this.snapToGrid(position);
		} else {
			if (this.vLine)
				this.vLine.hide();
			if (this.hLine)
				this.hLine.hide();
		}

		// Adjust the point by the zoom faktor
		position.x /= this.faktorXY.x;
		position.y /= this.faktorXY.y;

		// Set that the position is not lower than zero
		position.x = Math.max(0, position.x)
		position.y = Math.max(0, position.y)

		// Set that the position is not bigger than the canvas
		var c = this.facade.getCanvas();
		position.x = Math.min(c.bounds.width() - this.dragBounds.width(),
				position.x)
		position.y = Math.min(c.bounds.height() - this.dragBounds.height(),
				position.y)

		// Drag this bounds
		this.dragBounds.moveTo(position);

		// Update all selected shapes and the selection rectangle
		// this.refreshSelectedShapes();
		this.resizeRectangle(this.dragBounds);

		this.isAttachingAllowed = false;

		// check, if a node can be added to the underlying node
		var eventCoordinates = this.facade.eventCoordinates(event);

		var additionalIEZoom = 1;
		if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
			var ua = navigator.userAgent;
			if (ua.indexOf('MSIE') >= 0) {
				// IE 10 and below
				var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI)
						* 100);
				if (zoom !== 100) {
					additionalIEZoom = zoom / 100
				}
			}
		}

		if (additionalIEZoom !== 1) {
			eventCoordinates.x = eventCoordinates.x / additionalIEZoom;
			eventCoordinates.y = eventCoordinates.y / additionalIEZoom;
		}

		var underlyingNodes = $A(this.facade.getCanvas()
				.getAbstractShapesAtPosition(eventCoordinates));

		var checkIfAttachable = this.toMoveShapes.length == 1
				&& this.toMoveShapes[0] instanceof ORYX.Core.Node
				&& this.toMoveShapes[0].dockers.length > 0
		checkIfAttachable = checkIfAttachable && underlyingNodes.length != 1

		if (!checkIfAttachable
				&& underlyingNodes.length === this._currentUnderlyingNodes.length
				&& underlyingNodes.all(function(node, index) {
							return this._currentUnderlyingNodes[index] === node
						}.bind(this))) {

			return

		} else if (this._onlyEdges) {

			this.isAddingAllowed = true;
			this.containmentParentNode = this.facade.getCanvas();

		} else {

			/* Check the containment and connection rules */
			var options = {
				event : event,
				underlyingNodes : underlyingNodes,
				checkIfAttachable : checkIfAttachable
			};
			this.checkRules(options);

		}

		this._currentUnderlyingNodes = underlyingNodes.reverse();

		// visualize the containment result
		if (this.isAttachingAllowed) {

			this.facade.raiseEvent({
						type : ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
						highlightId : "dragdropresize.attached",
						elements : [this.containmentParentNode],
						style : ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE,
						color : ORYX.CONFIG.SELECTION_VALID_COLOR
					});

		} else {

			this.facade.raiseEvent({
						type : ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
						highlightId : "dragdropresize.attached"
					});
		}

		if (!this.isAttachingAllowed) {
			if (this.isAddingAllowed) {

				this.facade.raiseEvent({
							type : ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
							highlightId : "dragdropresize.contain",
							elements : [this.containmentParentNode],
							color : ORYX.CONFIG.SELECTION_VALID_COLOR
						});

			} else {

				this.facade.raiseEvent({
							type : ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
							highlightId : "dragdropresize.contain",
							elements : [this.containmentParentNode],
							color : ORYX.CONFIG.SELECTION_INVALID_COLOR
						});

			}
		} else {
			this.facade.raiseEvent({
						type : ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
						highlightId : "dragdropresize.contain"
					});
		}

		// Stop the Event
		// Event.stop(event);
		return;
	},

	// /**
	// * Rollbacks the docked shape of an edge, if the edge is not movable.
	// */
	// redockEdges: function() {
	// this._undockedEdgesCommand.dockers.each(function(el){
	// el.docker.setDockedShape(el.dockedShape);
	// el.docker.setReferencePoint(el.refPoint);
	// })
	// },

	/**
	 * Checks the containment and connection rules for the selected shapes.
	 */
	checkRules : function(options) {
		var event = options.event;
		var underlyingNodes = options.underlyingNodes;
		var checkIfAttachable = options.checkIfAttachable;
		var noEdges = options.noEdges;

		// get underlying node that is not the same than one of the currently
		// selected shapes or
		// a child of one of the selected shapes with the highest z Order.
		// The result is a shape or the canvas
		this.containmentParentNode = underlyingNodes.reverse().find(
				(function(node) {
					return (node instanceof ORYX.Core.Canvas)
							|| (((node instanceof ORYX.Core.Node) || ((node instanceof ORYX.Core.Edge) && !noEdges)) && (!(this.currentShapes
									.member(node) || this.currentShapes.any(
									function(shape) {
										return (shape.children.length > 0 && shape
												.getChildNodes(true)
												.member(node));
									}))));
				}).bind(this));

		if (checkIfAttachable) {

			this.isAttachingAllowed = this.facade.getRules().canConnect({
						sourceShape : this.containmentParentNode,
						edgeShape : this.toMoveShapes[0],
						targetShape : this.toMoveShapes[0]
					});

			if (this.isAttachingAllowed) {
				var point = this.facade.eventCoordinates(event);
				this.isAttachingAllowed = this.containmentParentNode
						.isPointOverOffset(point.x, point.y);
			}
		}

		if (!this.isAttachingAllowed) {
			// check all selected shapes, if they can be added to
			// containmentParentNode
			this.isAddingAllowed = this.toMoveShapes.all(
					(function(currentShape) {
						if (currentShape instanceof ORYX.Core.Edge
								|| currentShape instanceof ORYX.Core.Controls.Docker
								|| this.containmentParentNode === currentShape.parent) {
							return true;
						} else if (this.containmentParentNode !== currentShape) {

							if (!(this.containmentParentNode instanceof ORYX.Core.Edge)
									|| !noEdges) {

								if (this.facade.getRules().canContain({
									containingShape : this.containmentParentNode,
									containedShape : currentShape
								})) {
									return true;
								}
							}
						}
						return false;
					}).bind(this));
		}

		if (!this.isAttachingAllowed && !this.isAddingAllowed
				&& (this.containmentParentNode instanceof ORYX.Core.Edge)) {
			options.noEdges = true;
			options.underlyingNodes.reverse();
			this.checkRules(options);
		}
	},

	/**
	 * Redraw the selected Shapes.
	 * 
	 */
	refreshSelectedShapes : function() {
		// If the selection bounds not initialized, return
		if (!this.dragBounds) {
			return
		}

		// Calculate the offset between the bounds and the old bounds
		var upL = this.dragBounds.upperLeft();
		var oldUpL = this.oldDragBounds.upperLeft();
		var offset = {
			x : upL.x - oldUpL.x,
			y : upL.y - oldUpL.y
		};

		// Instanciate the dragCommand
		var commands = [new ORYX.Core.Command.Move(this.toMoveShapes, offset,
				this.containmentParentNode, this.currentShapes, this)];
		// If the undocked edges command is setted, add this command
		if (this._undockedEdgesCommand instanceof ORYX.Core.Command) {
			commands.unshift(this._undockedEdgesCommand);
		}
		// Execute the commands
		this.facade.executeCommands(commands);

		// copy the bounds to the old bounds
		if (this.dragBounds)
			this.oldDragBounds = this.dragBounds.clone();

	},

	/**
	 * Callback for Resize
	 * 
	 */
	onResize : function(bounds) {
		// If the selection bounds not initialized, return
		if (!this.dragBounds) {
			return
		}

		this.dragBounds = bounds;
		this.isResizing = true;

		// Update the rectangle
		this.resizeRectangle(this.dragBounds);
	},

	onResizeStart : function() {
		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_RESIZE_START
				});
	},

	onResizeEnd : function() {

		if (!(this.currentShapes instanceof Array)
				|| this.currentShapes.length <= 0) {
			return;
		}

		// If Resizing finished, the Shapes will be resize
		if (this.isResizing) {

			var commandClass = ORYX.Core.Command.extend({
				construct : function(shape, newBounds, plugin) {
					this.shape = shape;
					this.oldBounds = shape.bounds.clone();
					this.newBounds = newBounds;
					this.plugin = plugin;
				},
				execute : function() {
					this.shape.bounds.set(this.newBounds.a, this.newBounds.b);
					this.update(this.getOffset(this.oldBounds, this.newBounds));

				},
				rollback : function() {
					this.shape.bounds.set(this.oldBounds.a, this.oldBounds.b);
					this.update(this.getOffset(this.newBounds, this.oldBounds))
				},

				getOffset : function(b1, b2) {
					return {
						x : b2.a.x - b1.a.x,
						y : b2.a.y - b1.a.y,
						xs : b2.width() / b1.width(),
						ys : b2.height() / b1.height()
					}
				},
				update : function(offset) {
					this.shape.getLabels().each(function(label) {
								label.changed();
							});

					var allEdges = [].concat(this.shape.getIncomingShapes())
							.concat(this.shape.getOutgoingShapes())
							// Remove all edges which are included in the
							// selection from the list
							.findAll(function(r) {
										return r instanceof ORYX.Core.Edge
									}.bind(this))

					this.plugin.layoutEdges(this.shape, allEdges, offset);

					this.plugin.facade.setSelection([this.shape]);
					this.plugin.facade.getCanvas().update();
					this.plugin.facade.updateSelection();
				}
			});

			var bounds = this.dragBounds.clone();
			var shape = this.currentShapes[0];

			if (shape.parent) {
				var parentPosition = shape.parent.absoluteXY();
				bounds.moveBy(-parentPosition.x, -parentPosition.y);
			}

			var command = new commandClass(shape, bounds, this);

			this.facade.executeCommands([command]);

			this.isResizing = false;

			this.facade.raiseEvent({
						type : ORYX.CONFIG.EVENT_RESIZE_END
					});
		}
	},

	/**
	 * Prepare the Dragging
	 * 
	 */
	beforeDrag : function() {

		var undockEdgeCommand = ORYX.Core.Command.extend({
					construct : function(moveShapes) {
						this.dockers = moveShapes.collect(function(shape) {
							return shape instanceof ORYX.Core.Controls.Docker
									? {
										docker : shape,
										dockedShape : shape.getDockedShape(),
										refPoint : shape.referencePoint
									}
									: undefined
						}).compact();
					},
					execute : function() {
						this.dockers.each(function(el) {
									el.docker.setDockedShape(undefined);
								})
					},
					rollback : function() {
						this.dockers.each(function(el) {
							el.docker.setDockedShape(el.dockedShape);
							el.docker.setReferencePoint(el.refPoint);
								// el.docker.update();
							})
					}
				});

		this._undockedEdgesCommand = new undockEdgeCommand(this.toMoveShapes);
		this._undockedEdgesCommand.execute();

	},

	hideAllLabels : function(shape) {

		// Hide all labels from the shape
		shape.getLabels().each(function(label) {
					label.hide();
				});
		// Hide all labels from docked shapes
		shape.getAllDockedShapes().each(function(dockedShape) {
					var labels = dockedShape.getLabels();
					if (labels.length > 0) {
						labels.each(function(label) {
									label.hide();
								});
					}
				});

		// Do this recursive for all child shapes
		// EXP-NICO use getShapes
		shape.getChildren().each((function(value) {
					if (value instanceof ORYX.Core.Shape)
						this.hideAllLabels(value);
				}).bind(this));
	},

	/**
	 * Finished the Dragging
	 * 
	 */
	afterDrag : function() {

	},

	/**
	 * Show all Labels at these shape
	 * 
	 */
	showAllLabels : function(shape) {

		// Show the label of these shape
		// shape.getLabels().each(function(label) {
		for (var i = 0; i < shape.length; i++) {
			var label = shape[i];
			label.show();
		}// );
		// Show all labels at docked shapes
		// shape.getAllDockedShapes().each(function(dockedShape) {
		var allDockedShapes = shape.getAllDockedShapes()
		for (var i = 0; i < allDockedShapes.length; i++) {
			var dockedShape = allDockedShapes[i];
			var labels = dockedShape.getLabels();
			if (labels.length > 0) {
				labels.each(function(label) {
							label.show();
						});
			}
		}// );

		// Do this recursive
		// shape.children.each((function(value) {
		for (var i = 0; i < shape.children.length; i++) {
			var value = shape.children[i];
			if (value instanceof ORYX.Core.Shape)
				this.showAllLabels(value);
		}// ).bind(this));
	},

	/**
	 * Intialize Method, if there are new Plugins
	 * 
	 */
	/*
	 * registryChanged: function(pluginsData) { // Save all new Plugin, sorted
	 * by group and index this.pluginsData = pluginsData.sortBy( function(value) {
	 * return (value.group + "" + value.index); }); },
	 */

	/**
	 * On the Selection-Changed
	 * 
	 */
	onSelectionChanged : function(event) {
		var elements = event.elements;

		// Reset the drag-variables
		this.dragEnable = false;
		this.dragIntialized = false;
		this.resizerSE.hide();
		this.resizerNW.hide();

		// If there is no elements
		if (!elements || elements.length == 0) {
			// Hide all things and reset all variables
			this.selectedRect.hide();
			this.currentShapes = [];
			this.toMoveShapes = [];
			this.dragBounds = undefined;
			this.oldDragBounds = undefined;
		} else {

			// Set the current Shapes
			this.currentShapes = elements;

			// Get all shapes with the highest parent in object hierarchy
			// (canvas is the top most parent)
			var topLevelElements = this.facade.getCanvas()
					.getShapesWithSharedParent(elements);
			this.toMoveShapes = topLevelElements;

			this.toMoveShapes = this.toMoveShapes.findAll(function(shape) {
				return shape instanceof ORYX.Core.Node
						&& (shape.dockers.length === 0 || !elements
								.member(shape.dockers.first().getDockedShape()))
			});

			elements.each((function(shape) {
						if (!(shape instanceof ORYX.Core.Edge)) {
							return;
						}

						var dks = shape.getDockers();

						var hasF = elements
								.member(dks.first().getDockedShape());
						var hasL = elements.member(dks.last().getDockedShape());

						// if(!hasL) {
						// this.toMoveShapes.push(dks.last());
						// }
						// if(!hasF){
						// this.toMoveShapes.push(dks.first())
						// }
						/* Enable movement of undocked edges */
						if (!hasF && !hasL) {
							var isUndocked = !dks.first().getDockedShape()
									&& !dks.last().getDockedShape();
							if (isUndocked) {
								this.toMoveShapes = this.toMoveShapes
										.concat(dks);
							}
						}

						if (shape.dockers.length > 2 && hasF && hasL) {
							this.toMoveShapes = this.toMoveShapes.concat(dks
									.findAll(function(el, index) {
												return index > 0
														&& index < dks.length
																- 1
											}));
						}

					}).bind(this));

			// Calculate the new area-bounds of the selection
			var newBounds = undefined;
			this.toMoveShapes.each(function(value) {
						var shape = value;
						if (value instanceof ORYX.Core.Controls.Docker) {
							/* Get the Shape */
							shape = value.parent;
						}

						if (!newBounds) {
							newBounds = shape.absoluteBounds();
						} else {
							newBounds.include(shape.absoluteBounds());
						}
					}.bind(this));

			if (!newBounds) {
				elements.each(function(value) {
							if (!newBounds) {
								newBounds = value.absoluteBounds();
							} else {
								newBounds.include(value.absoluteBounds());
							}
						});
			}

			// Set the new bounds
			this.dragBounds = newBounds;
			this.oldDragBounds = newBounds.clone();

			// Update and show the rectangle
			this.resizeRectangle(newBounds);
			this.selectedRect.show();

			// Show the resize button, if there is only one element and this is
			// resizeable
			if (elements.length == 1 && elements[0].isResizable) {
				var aspectRatio = elements[0].getStencil().fixedAspectRatio()
						? elements[0].bounds.width()
								/ elements[0].bounds.height()
						: undefined;
				this.resizerSE.setBounds(this.dragBounds,
						elements[0].minimumSize, elements[0].maximumSize,
						aspectRatio);
				this.resizerSE.show();
				this.resizerNW.setBounds(this.dragBounds,
						elements[0].minimumSize, elements[0].maximumSize,
						aspectRatio);
				this.resizerNW.show();
			} else {
				this.resizerSE.setBounds(undefined);
				this.resizerNW.setBounds(undefined);
			}

			// If Snap-To-Grid is enabled, the Snap-Point will be calculate
			if (ORYX.CONFIG.GRID_ENABLED) {

				// Reset all points
				this.distPoints = [];

				if (this.distPointTimeout)
					window.clearTimeout(this.distPointTimeout)

				this.distPointTimeout = window.setTimeout(function() {
							// Get all the shapes, there will consider at
							// snapping
							// Consider only those elements who shares the same
							// parent element
							var distShapes = this.facade.getCanvas()
									.getChildShapes(true).findAll(
											function(value) {
												var parentShape = value.parent;
												while (parentShape) {
													if (elements
															.member(parentShape))
														return false;
													parentShape = parentShape.parent
												}
												return true;
											})

							// The current selection will delete from this array
							// elements.each(function(shape) {
							// distShapes = distShapes.without(shape);
							// });

							// For all these shapes
							distShapes.each((function(value) {
										if (!(value instanceof ORYX.Core.Edge)) {
											var ul = value.absoluteXY();
											var width = value.bounds.width();
											var height = value.bounds.height();

											// Add the upperLeft, center and
											// lowerRight - Point to the
											// distancePoints
											this.distPoints.push({
														ul : {
															x : ul.x,
															y : ul.y
														},
														c : {
															x : ul.x
																	+ (width / 2),
															y : ul.y
																	+ (height / 2)
														},
														lr : {
															x : ul.x + width,
															y : ul.y + height
														}
													});
										}
									}).bind(this));

						}.bind(this), 10)

			}
		}
	},

	/**
	 * Adjust an Point to the Snap Points
	 * 
	 */
	snapToGrid : function(position) {

		// Get the current Bounds
		var bounds = this.dragBounds;

		var point = {};

		var ulThres = 6;
		var cThres = 10;
		var lrThres = 6;

		var scale = this.vLine ? this.vLine.getScale() : 1;

		var ul = {
			x : (position.x / scale),
			y : (position.y / scale)
		};
		var c = {
			x : (position.x / scale) + (bounds.width() / 2),
			y : (position.y / scale) + (bounds.height() / 2)
		};
		var lr = {
			x : (position.x / scale) + (bounds.width()),
			y : (position.y / scale) + (bounds.height())
		};

		var offsetX, offsetY;
		var gridX, gridY;

		// For each distant point
		this.distPoints.each(function(value) {

					var x, y, gx, gy;
					if (Math.abs(value.c.x - c.x) < cThres) {
						x = value.c.x - c.x;
						gx = value.c.x;
					}/*
						 * else if (Math.abs(value.ul.x-ul.x) < ulThres){ x =
						 * value.ul.x-ul.x; gx = value.ul.x; } else if
						 * (Math.abs(value.lr.x-lr.x) < lrThres){ x =
						 * value.lr.x-lr.x; gx = value.lr.x; }
						 */

					if (Math.abs(value.c.y - c.y) < cThres) {
						y = value.c.y - c.y;
						gy = value.c.y;
					}/*
						 * else if (Math.abs(value.ul.y-ul.y) < ulThres){ y =
						 * value.ul.y-ul.y; gy = value.ul.y; } else if
						 * (Math.abs(value.lr.y-lr.y) < lrThres){ y =
						 * value.lr.y-lr.y; gy = value.lr.y; }
						 */

					if (x !== undefined) {
						offsetX = offsetX === undefined
								? x
								: (Math.abs(x) < Math.abs(offsetX)
										? x
										: offsetX);
						if (offsetX === x)
							gridX = gx;
					}

					if (y !== undefined) {
						offsetY = offsetY === undefined
								? y
								: (Math.abs(y) < Math.abs(offsetY)
										? y
										: offsetY);
						if (offsetY === y)
							gridY = gy;
					}
				});

		if (offsetX !== undefined) {
			ul.x += offsetX;
			ul.x *= scale;
			if (this.vLine && gridX)
				this.vLine.update(gridX);
		} else {
			ul.x = (position.x - (position.x % (ORYX.CONFIG.GRID_DISTANCE / 2)));
			if (this.vLine)
				this.vLine.hide()
		}

		if (offsetY !== undefined) {
			ul.y += offsetY;
			ul.y *= scale;
			if (this.hLine && gridY)
				this.hLine.update(gridY);
		} else {
			ul.y = (position.y - (position.y % (ORYX.CONFIG.GRID_DISTANCE / 2)));
			if (this.hLine)
				this.hLine.hide();
		}

		return ul;
	},

	showGridLine : function() {

	},

	/**
	 * Redraw of the Rectangle of the SelectedArea
	 * 
	 * @param {Object}
	 *            bounds
	 */
	resizeRectangle : function(bounds) {
		// Resize the Rectangle
		this.selectedRect.resize(bounds);
	}

});

ORYX.Plugins.SelectedRect = Clazz.extend({

			construct : function(parentId) {

				this.parentId = parentId;

				this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
						$(parentId), ['g']);

				this.dashedArea = ORYX.Editor.graft(
						"http://www.w3.org/2000/svg", this.node, ['rect', {
									x : 0,
									y : 0,
									'stroke-width' : 1,
									stroke : '#777777',
									fill : 'none',
									'stroke-dasharray' : '2,2',
									'pointer-events' : 'none'
								}]);

				this.hide();

			},

			hide : function() {
				this.node.setAttributeNS(null, 'display', 'none');
			},

			show : function() {
				this.node.setAttributeNS(null, 'display', '');
			},

			resize : function(bounds) {
				var upL = bounds.upperLeft();

				var padding = ORYX.CONFIG.SELECTED_AREA_PADDING;

				this.dashedArea.setAttributeNS(null, 'width', bounds.width()
								+ 2 * padding);
				this.dashedArea.setAttributeNS(null, 'height', bounds.height()
								+ 2 * padding);
				this.node.setAttributeNS(null, 'transform', "translate("
								+ (upL.x - padding) + ", " + (upL.y - padding)
								+ ")");
			}

		});

ORYX.Plugins.GridLine = Clazz.extend({

	construct : function(parentId, direction) {

		if (ORYX.Plugins.GridLine.DIR_HORIZONTAL !== direction
				&& ORYX.Plugins.GridLine.DIR_VERTICAL !== direction) {
			direction = ORYX.Plugins.GridLine.DIR_HORIZONTAL
		}

		this.parent = $(parentId);
		this.direction = direction;
		this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
				this.parent, ['g']);

		this.line = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node,
				['path', {
							'stroke-width' : 1,
							stroke : 'silver',
							fill : 'none',
							'stroke-dasharray' : '5,5',
							'pointer-events' : 'none'
						}]);

		this.hide();

	},

	hide : function() {
		this.node.setAttributeNS(null, 'display', 'none');
	},

	show : function() {
		this.node.setAttributeNS(null, 'display', '');
	},

	getScale : function() {
		try {
			return this.parent.parentNode.transform.baseVal.getItem(0).matrix.a;
		} catch (e) {
			return 1;
		}
	},

	update : function(pos) {

		if (this.direction === ORYX.Plugins.GridLine.DIR_HORIZONTAL) {
			var y = pos instanceof Object ? pos.y : pos;
			var cWidth = this.parent.parentNode.parentNode.width.baseVal.value
					/ this.getScale();
			this.line.setAttributeNS(null, 'd', 'M 0 ' + y + ' L ' + cWidth
							+ ' ' + y);
		} else {
			var x = pos instanceof Object ? pos.x : pos;
			var cHeight = this.parent.parentNode.parentNode.height.baseVal.value
					/ this.getScale();
			this.line.setAttributeNS(null, 'd', 'M' + x + ' 0 L ' + x + ' '
							+ cHeight);
		}

		this.show();
	}

});

ORYX.Plugins.GridLine.DIR_HORIZONTAL = "hor";
ORYX.Plugins.GridLine.DIR_VERTICAL = "ver";

ORYX.Plugins.Resizer = Clazz.extend({

	construct : function(parentId, orientation, facade) {

		this.parentId = parentId;
		this.orientation = orientation;
		this.facade = facade;

		this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml",
				$('canvasSection'), ['div', {
							'class' : 'resizer_' + this.orientation,
							style : 'left:0px; top:0px;position:absolute;'
						}]);

		this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN,
				this.handleMouseDown.bind(this), true);
		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP,
				this.handleMouseUp.bind(this), true);
		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE,
				this.handleMouseMove.bind(this), false);

		this.dragEnable = false;
		this.offSetPosition = {
			x : 0,
			y : 0
		};
		this.bounds = undefined;

		this.canvasNode = this.facade.getCanvas().node;

		this.minSize = undefined;
		this.maxSize = undefined;

		this.aspectRatio = undefined;

		this.resizeCallbacks = [];
		this.resizeStartCallbacks = [];
		this.resizeEndCallbacks = [];
		this.hide();

		// Calculate the Offset
		this.scrollNode = this.node.parentNode.parentNode.parentNode;

	},

	handleMouseDown : function(event) {
		this.dragEnable = true;

		this.offsetScroll = {
			x : this.scrollNode.scrollLeft,
			y : this.scrollNode.scrollTop
		};

		this.offSetPosition = {
			x : Event.pointerX(event) - this.position.x,
			y : Event.pointerY(event) - this.position.y
		};

		this.resizeStartCallbacks.each((function(value) {
					value(this.bounds);
				}).bind(this));

	},

	handleMouseUp : function(event) {
		this.dragEnable = false;
		this.containmentParentNode = null;
		this.resizeEndCallbacks.each((function(value) {
					value(this.bounds);
				}).bind(this));

	},

	handleMouseMove : function(event) {
		if (!this.dragEnable) {
			return
		}

		if (event.shiftKey || event.ctrlKey) {
			this.aspectRatio = this.bounds.width() / this.bounds.height();
		} else {
			this.aspectRatio = undefined;
		}

		var position = {
			x : Event.pointerX(event) - this.offSetPosition.x,
			y : Event.pointerY(event) - this.offSetPosition.y
		};

		position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft;
		position.y -= this.offsetScroll.y - this.scrollNode.scrollTop;

		position.x = Math.min(position.x, this.facade.getCanvas().bounds
						.width());
		position.y = Math.min(position.y, this.facade.getCanvas().bounds
						.height());

		var offset = {
			x : position.x - this.position.x,
			y : position.y - this.position.y
		};

		if (this.aspectRatio) {
			// fixed aspect ratio
			newAspectRatio = (this.bounds.width() + offset.x)
					/ (this.bounds.height() + offset.y);
			if (newAspectRatio > this.aspectRatio) {
				offset.x = this.aspectRatio * (this.bounds.height() + offset.y)
						- this.bounds.width();
			} else if (newAspectRatio < this.aspectRatio) {
				offset.y = (this.bounds.width() + offset.x) / this.aspectRatio
						- this.bounds.height();
			}
		}

		// respect minimum and maximum sizes of stencil
		if (this.orientation === "northwest") {

			if (this.bounds.width() - offset.x > this.maxSize.width) {
				offset.x = -(this.maxSize.width - this.bounds.width());
				if (this.aspectRatio)
					offset.y = this.aspectRatio * offset.x;
			}
			if (this.bounds.width() - offset.x < this.minSize.width) {
				offset.x = -(this.minSize.width - this.bounds.width());
				if (this.aspectRatio)
					offset.y = this.aspectRatio * offset.x;
			}
			if (this.bounds.height() - offset.y > this.maxSize.height) {
				offset.y = -(this.maxSize.height - this.bounds.height());
				if (this.aspectRatio)
					offset.x = offset.y / this.aspectRatio;
			}
			if (this.bounds.height() - offset.y < this.minSize.height) {
				offset.y = -(this.minSize.height - this.bounds.height());
				if (this.aspectRatio)
					offset.x = offset.y / this.aspectRatio;
			}

		} else { // defaults to southeast
			if (this.bounds.width() + offset.x > this.maxSize.width) {
				offset.x = this.maxSize.width - this.bounds.width();
				if (this.aspectRatio)
					offset.y = this.aspectRatio * offset.x;
			}
			if (this.bounds.width() + offset.x < this.minSize.width) {
				offset.x = this.minSize.width - this.bounds.width();
				if (this.aspectRatio)
					offset.y = this.aspectRatio * offset.x;
			}
			if (this.bounds.height() + offset.y > this.maxSize.height) {
				offset.y = this.maxSize.height - this.bounds.height();
				if (this.aspectRatio)
					offset.x = offset.y / this.aspectRatio;
			}
			if (this.bounds.height() + offset.y < this.minSize.height) {
				offset.y = this.minSize.height - this.bounds.height();
				if (this.aspectRatio)
					offset.x = offset.y / this.aspectRatio;
			}
		}

		if (this.orientation === "northwest") {
			this.bounds.extend({
						x : -offset.x,
						y : -offset.y
					});
			this.bounds.moveBy(offset);
		} else { // defaults to southeast
			this.bounds.extend(offset);
		}

		this.update();

		this.resizeCallbacks.each((function(value) {
					value(this.bounds);
				}).bind(this));

		Event.stop(event);

	},

	registerOnResizeStart : function(callback) {
		if (!this.resizeStartCallbacks.member(callback)) {
			this.resizeStartCallbacks.push(callback);
		}
	},

	unregisterOnResizeStart : function(callback) {
		if (this.resizeStartCallbacks.member(callback)) {
			this.resizeStartCallbacks = this.resizeStartCallbacks
					.without(callback);
		}
	},

	registerOnResizeEnd : function(callback) {
		if (!this.resizeEndCallbacks.member(callback)) {
			this.resizeEndCallbacks.push(callback);
		}
	},

	unregisterOnResizeEnd : function(callback) {
		if (this.resizeEndCallbacks.member(callback)) {
			this.resizeEndCallbacks = this.resizeEndCallbacks.without(callback);
		}
	},

	registerOnResize : function(callback) {
		if (!this.resizeCallbacks.member(callback)) {
			this.resizeCallbacks.push(callback);
		}
	},

	unregisterOnResize : function(callback) {
		if (this.resizeCallbacks.member(callback)) {
			this.resizeCallbacks = this.resizeCallbacks.without(callback);
		}
	},

	hide : function() {
		this.node.style.display = "none";
	},

	show : function() {
		if (this.bounds)
			this.node.style.display = "";
	},

	setBounds : function(bounds, min, max, aspectRatio) {
		this.bounds = bounds;

		if (!min)
			min = {
				width : ORYX.CONFIG.MINIMUM_SIZE,
				height : ORYX.CONFIG.MINIMUM_SIZE
			};

		if (!max)
			max = {
				width : ORYX.CONFIG.MAXIMUM_SIZE,
				height : ORYX.CONFIG.MAXIMUM_SIZE
			};

		this.minSize = min;
		this.maxSize = max;

		this.aspectRatio = aspectRatio;

		this.update();
	},

	update : function() {
		if (!this.bounds) {
			return;
		}

		var upL = this.bounds.upperLeft();

		if (this.bounds.width() < this.minSize.width) {
			this.bounds.set(upL.x, upL.y, upL.x + this.minSize.width, upL.y
							+ this.bounds.height());
		};
		if (this.bounds.height() < this.minSize.height) {
			this.bounds.set(upL.x, upL.y, upL.x + this.bounds.width(), upL.y
							+ this.minSize.height);
		};
		if (this.bounds.width() > this.maxSize.width) {
			this.bounds.set(upL.x, upL.y, upL.x + this.maxSize.width, upL.y
							+ this.bounds.height());
		};
		if (this.bounds.height() > this.maxSize.height) {
			this.bounds.set(upL.x, upL.y, upL.x + this.bounds.width(), upL.y
							+ this.maxSize.height);
		};

		var a = this.canvasNode.getScreenCTM();

		upL.x *= a.a;
		upL.y *= a.d;

		var additionalIEZoom = 1;
		if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
			var ua = navigator.userAgent;
			if (ua.indexOf('MSIE') >= 0) {
				// IE 10 and below
				var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI)
						* 100);
				if (zoom !== 100) {
					additionalIEZoom = zoom / 100
				}
			}
		}

		if (additionalIEZoom === 1) {
			upL.y = upL.y - jQuery("#canvasSection").offset().top + a.f;
			upL.x = upL.x - jQuery("#canvasSection").offset().left + a.e;

		} else {
			var canvasOffsetLeft = jQuery("#canvasSection").offset().left;
			var canvasScrollLeft = jQuery("#canvasSection").scrollLeft();
			var canvasScrollTop = jQuery("#canvasSection").scrollTop();

			var offset = a.e - (canvasOffsetLeft * additionalIEZoom);
			var additionaloffset = 0;
			if (offset > 10) {
				additionaloffset = (offset / additionalIEZoom) - offset;
			}
			upL.y = upL.y
					- (jQuery("#canvasSection").offset().top * additionalIEZoom)
					+ ((canvasScrollTop * additionalIEZoom) - canvasScrollTop)
					+ a.f;
			upL.x = upL.x
					- (canvasOffsetLeft * additionalIEZoom)
					+ additionaloffset
					+ ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft)
					+ a.e;
		}

		if (this.orientation === "northwest") {
			upL.x -= 13;
			upL.y -= 13;
		} else { // defaults to southeast
			upL.x += (a.a * this.bounds.width()) + 3;
			upL.y += (a.d * this.bounds.height()) + 3;
		}

		this.position = upL;

		this.node.style.left = this.position.x + "px";
		this.node.style.top = this.position.y + "px";
	}
});

/**
 * Implements a Command to move shapes
 * 
 */
ORYX.Core.Command.Move = ORYX.Core.Command.extend({
	construct : function(moveShapes, offset, parent, selectedShapes, plugin) {
		this.moveShapes = moveShapes;
		this.selectedShapes = selectedShapes;
		this.offset = offset;
		this.plugin = plugin;
		// Defines the old/new parents for the particular shape
		this.newParents = moveShapes.collect(function(t) {
					return parent || t.parent
				});
		this.oldParents = moveShapes.collect(function(shape) {
					return shape.parent
				});
		this.dockedNodes = moveShapes.findAll(function(shape) {
					return shape instanceof ORYX.Core.Node
							&& shape.dockers.length == 1
				}).collect(function(shape) {
					return {
						docker : shape.dockers[0],
						dockedShape : shape.dockers[0].getDockedShape(),
						refPoint : shape.dockers[0].referencePoint
					}
				});
	},
	execute : function() {
		this.dockAllShapes()
		// Moves by the offset
		this.move(this.offset);
		// Addes to the new parents
		this.addShapeToParent(this.newParents);
		// Set the selection to the current selection
		this.selectCurrentShapes();
		this.plugin.facade.getCanvas().update();
		this.plugin.facade.updateSelection();
	},
	rollback : function() {
		// Moves by the inverted offset
		var offset = {
			x : -this.offset.x,
			y : -this.offset.y
		};
		this.move(offset);
		// Addes to the old parents
		this.addShapeToParent(this.oldParents);
		this.dockAllShapes(true)

		// Set the selection to the current selection
		this.selectCurrentShapes();
		this.plugin.facade.getCanvas().update();
		this.plugin.facade.updateSelection();

	},
	move : function(offset, doLayout) {

		// Move all Shapes by these offset
		for (var i = 0; i < this.moveShapes.length; i++) {
			var value = this.moveShapes[i];
			value.bounds.moveBy(offset);

			if (value instanceof ORYX.Core.Node) {

				(value.dockers || []).each(function(d) {
							d.bounds.moveBy(offset);
						})

				// Update all Dockers of Child shapes
				/*
				 * var childShapesNodes =
				 * value.getChildShapes(true).findAll(function(shape){ return
				 * shape instanceof ORYX.Core.Node }); var childDockedShapes =
				 * childShapesNodes.collect(function(shape){ return
				 * shape.getAllDockedShapes() }).flatten().uniq(); var
				 * childDockedEdge = childDockedShapes.findAll(function(shape){
				 * return shape instanceof ORYX.Core.Edge }); childDockedEdge =
				 * childDockedEdge.findAll(function(shape){ return
				 * shape.getAllDockedShapes().all(function(dsh){ return
				 * childShapesNodes.include(dsh) }) }); var childDockedDockers =
				 * childDockedEdge.collect(function(shape){ return shape.dockers
				 * }).flatten();
				 * 
				 * for (var j = 0; j < childDockedDockers.length; j++) { var
				 * docker = childDockedDockers[j]; if (!docker.getDockedShape() &&
				 * !this.moveShapes.include(docker)) {
				 * //docker.bounds.moveBy(offset); //docker.update(); } }
				 */

				var allEdges = [].concat(value.getIncomingShapes())
						.concat(value.getOutgoingShapes())
						// Remove all edges which are included in the selection
						// from the list
						.findAll(function(r) {
							return r instanceof ORYX.Core.Edge
									&& !this.moveShapes.any(function(d) {
										return d == r
												|| (d instanceof ORYX.Core.Controls.Docker && d.parent == r)
									})
						}.bind(this))
						// Remove all edges which are between the node and a
						// node contained in the selection from the list
						.findAll(function(r) {
							return (r.dockers.first().getDockedShape() == value || !this.moveShapes
									.include(r.dockers.first().getDockedShape()))
									&& (r.dockers.last().getDockedShape() == value || !this.moveShapes
											.include(r.dockers.last()
													.getDockedShape()))
						}.bind(this))

				// Layout all outgoing/incoming edges
				this.plugin.layoutEdges(value, allEdges, offset);

				var allSameEdges = [].concat(value.getIncomingShapes())
						.concat(value.getOutgoingShapes())
						// Remove all edges which are included in the selection
						// from the list
						.findAll(function(r) {
							return r instanceof ORYX.Core.Edge
									&& r.dockers.first().isDocked()
									&& r.dockers.last().isDocked()
									&& !this.moveShapes.include(r)
									&& !this.moveShapes.any(function(d) {
										return d == r
												|| (d instanceof ORYX.Core.Controls.Docker && d.parent == r)
									})
						}.bind(this))
						// Remove all edges which are included in the selection
						// from the list
						.findAll(function(r) {
							return this.moveShapes.indexOf(r.dockers.first()
									.getDockedShape()) > i
									|| this.moveShapes.indexOf(r.dockers.last()
											.getDockedShape()) > i
						}.bind(this))

				for (var j = 0; j < allSameEdges.length; j++) {
					for (var k = 1; k < allSameEdges[j].dockers.length - 1; k++) {
						var docker = allSameEdges[j].dockers[k];
						if (!docker.getDockedShape()
								&& !this.moveShapes.include(docker)) {
							docker.bounds.moveBy(offset);
						}
					}
				}

				/*
				 * var i=-1; var nodes = value.getChildShapes(true); var
				 * allEdges = []; while(++i<nodes.length){ var edges =
				 * [].concat(nodes[i].getIncomingShapes())
				 * .concat(nodes[i].getOutgoingShapes()) // Remove all edges
				 * which are included in the selection from the list
				 * .findAll(function(r){ return r instanceof ORYX.Core.Edge &&
				 * !allEdges.include(r) && r.dockers.any(function(d){ return
				 * !value.bounds.isIncluded(d.bounds.center)})}) allEdges =
				 * allEdges.concat(edges); if (edges.length <= 0){ continue }
				 * //this.plugin.layoutEdges(nodes[i], edges, offset); }
				 */
			}
		}

	},
	dockAllShapes : function(shouldDocked) {
		// Undock all Nodes
		for (var i = 0; i < this.dockedNodes.length; i++) {
			var docker = this.dockedNodes[i].docker;

			docker.setDockedShape(shouldDocked
					? this.dockedNodes[i].dockedShape
					: undefined)
			if (docker.getDockedShape()) {
				docker.setReferencePoint(this.dockedNodes[i].refPoint);
				// docker.update();
			}
		}
	},

	addShapeToParent : function(parents) {

		// For every Shape, add this and reset the position
		for (var i = 0; i < this.moveShapes.length; i++) {
			var currentShape = this.moveShapes[i];
			if (currentShape instanceof ORYX.Core.Node
					&& currentShape.parent !== parents[i]) {

				// Calc the new position
				var unul = parents[i].absoluteXY();
				var csul = currentShape.absoluteXY();
				var x = csul.x - unul.x;
				var y = csul.y - unul.y;

				// Add the shape to the new contained shape
				parents[i].add(currentShape);
				// Add all attached shapes as well
				currentShape.getOutgoingShapes((function(shape) {
							if (shape instanceof ORYX.Core.Node
									&& !this.moveShapes.member(shape)) {
								parents[i].add(shape);
							}
						}).bind(this));

				// Set the new position
				if (currentShape instanceof ORYX.Core.Node
						&& currentShape.dockers.length == 1) {
					var b = currentShape.bounds;
					x += b.width() / 2;
					y += b.height() / 2
					currentShape.dockers.first().bounds.centerMoveTo(x, y);
				} else {
					currentShape.bounds.moveTo(x, y);
				}

			}

			// Update the shape
			// currentShape.update();

		}
	},
	selectCurrentShapes : function() {
		this.plugin.facade.setSelection(this.selectedShapes);
	}
});
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.DragDocker = Clazz.extend({

	/**
	 * Constructor
	 * 
	 * @param {Object}
	 *            Facade: The Facade of the Editor
	 */
	construct : function(facade) {
		this.facade = facade;

		// Set the valid and invalid color
		this.VALIDCOLOR = ORYX.CONFIG.SELECTION_VALID_COLOR;
		this.INVALIDCOLOR = ORYX.CONFIG.SELECTION_INVALID_COLOR;

		// Define Variables
		this.shapeSelection = undefined;
		this.docker = undefined;
		this.dockerParent = undefined;
		this.dockerSource = undefined;
		this.dockerTarget = undefined;
		this.lastUIObj = undefined;
		this.isStartDocker = undefined;
		this.isEndDocker = undefined;
		this.undockTreshold = 10;
		this.initialDockerPosition = undefined;
		this.outerDockerNotMoved = undefined;
		this.isValid = false;

		// For the Drag and Drop
		// Register on MouseDown-Event on a Docker
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN,
				this.handleMouseDown.bind(this));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DOCKERDRAG,
				this.handleDockerDrag.bind(this));

		// Register on over/out to show / hide a docker
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOVER,
				this.handleMouseOver.bind(this));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOUT,
				this.handleMouseOut.bind(this));

	},

	/**
	 * MouseOut Handler
	 * 
	 */
	handleMouseOut : function(event, uiObj) {
		// If there is a Docker, hide this
		if (!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) {
			uiObj.hide();
		} else if (!this.docker && uiObj instanceof ORYX.Core.Edge) {
			uiObj.dockers.each(function(docker) {
						docker.hide();
					});
		}
	},

	/**
	 * MouseOver Handler
	 * 
	 */
	handleMouseOver : function(event, uiObj) {
		// If there is a Docker, show this
		if (!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) {
			uiObj.show();
		} else if (!this.docker && uiObj instanceof ORYX.Core.Edge) {
			uiObj.dockers.each(function(docker) {
						docker.show();
					});
		}
	},
	/**
	 * DockerDrag Handler delegates the uiEvent of the drag event to the
	 * mouseDown function
	 */
	handleDockerDrag : function(event, uiObj) {
		this.handleMouseDown(event.uiEvent, uiObj);
	},

	/**
	 * MouseDown Handler
	 * 
	 */
	handleMouseDown : function(event, uiObj) {
		// If there is a Docker
		if (uiObj instanceof ORYX.Core.Controls.Docker && uiObj.isMovable) {

			/* Buffering shape selection and clear selection */
			this.shapeSelection = this.facade.getSelection();
			this.facade.setSelection();

			this.docker = uiObj;
			this.initialDockerPosition = this.docker.bounds.center();
			this.outerDockerNotMoved = false;
			this.dockerParent = uiObj.parent;

			// Define command arguments
			this._commandArg = {
				docker : uiObj,
				dockedShape : uiObj.getDockedShape(),
				refPoint : uiObj.referencePoint || uiObj.bounds.center()
			};

			// Show the Docker
			this.docker.show();

			// If the Dockers Parent is an Edge,
			// and the Docker is either the first or last Docker of the Edge
			if (uiObj.parent instanceof ORYX.Core.Edge
					&& (uiObj.parent.dockers.first() == uiObj || uiObj.parent.dockers
							.last() == uiObj)) {

				// Get the Edge Source or Target
				if (uiObj.parent.dockers.first() == uiObj
						&& uiObj.parent.dockers.last().getDockedShape()) {
					this.dockerTarget = uiObj.parent.dockers.last()
							.getDockedShape();
				} else if (uiObj.parent.dockers.last() == uiObj
						&& uiObj.parent.dockers.first().getDockedShape()) {
					this.dockerSource = uiObj.parent.dockers.first()
							.getDockedShape();
				}

			} else {
				// If there parent is not an Edge, undefined the Source and
				// Target
				this.dockerSource = undefined;
				this.dockerTarget = undefined;
			}

			this.isStartDocker = this.docker.parent.dockers.first() === this.docker;
			this.isEndDocker = this.docker.parent.dockers.last() === this.docker;

			// add to canvas while dragging
			this.facade.getCanvas().add(this.docker.parent);

			// Hide all Labels from Docker
			this.docker.parent.getLabels().each(function(label) {
						label.hide();
					});

			var eventCoordinates = this.facade.eventCoordinates(event);
			var additionalIEZoom = 1;
			if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
				var ua = navigator.userAgent;
				if (ua.indexOf('MSIE') >= 0) {
					// IE 10 and below
					var zoom = Math
							.round((screen.deviceXDPI / screen.logicalXDPI)
									* 100);
					if (zoom !== 100) {
						additionalIEZoom = zoom / 100
					}
				}
			}

			if (additionalIEZoom !== 1) {
				eventCoordinates.x = eventCoordinates.x / additionalIEZoom;
				eventCoordinates.y = eventCoordinates.y / additionalIEZoom;
			}

			// Undocked the Docker from current Shape
			if ((!this.isStartDocker && !this.isEndDocker)
					|| !this.docker.isDocked()) {

				this.docker.setDockedShape(undefined);
				// Set the Docker to the center of the mouse pointer
				this.docker.bounds.centerMoveTo(eventCoordinates);
				this.dockerParent._update();
			} else {
				this.outerDockerNotMoved = true;
			}

			var option = {
				movedCallback : this.dockerMoved.bind(this),
				upCallback : this.dockerMovedFinished.bind(this)
			};

			this.startEventPos = eventCoordinates;

			// Enable the Docker for Drag'n'Drop, give the mouseMove and
			// mouseUp-Callback with
			ORYX.Core.UIEnableDrag(event, uiObj, option);
		}
	},

	/**
	 * Docker MouseMove Handler
	 * 
	 */
	dockerMoved : function(event) {
		this.outerDockerNotMoved = false;
		var snapToMagnet = undefined;

		if (this.docker.parent) {
			if (this.isStartDocker || this.isEndDocker) {

				// Get the EventPosition and all Shapes on these point
				var evPos = this.facade.eventCoordinates(event);

				var additionalIEZoom = 1;
				if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
					var ua = navigator.userAgent;
					if (ua.indexOf('MSIE') >= 0) {
						// IE 10 and below
						var zoom = Math
								.round((screen.deviceXDPI / screen.logicalXDPI)
										* 100);
						if (zoom !== 100) {
							additionalIEZoom = zoom / 100
						}
					}
				}

				if (additionalIEZoom !== 1) {
					evPos.x = evPos.x / additionalIEZoom;
					evPos.y = evPos.y / additionalIEZoom;
				}

				if (this.docker.isDocked()) {
					/*
					 * Only consider start/end dockers if they are moved over a
					 * treshold
					 */
					var distanceDockerPointer = ORYX.Core.Math
							.getDistancePointToPoint(evPos,
									this.initialDockerPosition);
					if (distanceDockerPointer < this.undockTreshold) {
						this.outerDockerNotMoved = true;
						return;
					}

					/* Undock the docker */
					this.docker.setDockedShape(undefined);
					// Set the Docker to the center of the mouse pointer
					// this.docker.bounds.centerMoveTo(evPos);
					this.dockerParent._update();
				}

				var shapes = this.facade.getCanvas()
						.getAbstractShapesAtPosition(evPos);

				// Get the top level Shape on these, but not the same as Dockers
				// parent
				var uiObj = shapes.pop();
				if (this.docker.parent === uiObj) {
					uiObj = shapes.pop();
				}

				// If the top level Shape the same as the last Shape, then
				// return
				if (this.lastUIObj == uiObj) {
					// return;

					// If the top level uiObj instance of Shape and this isn't
					// the parent of the docker
				} else if (uiObj instanceof ORYX.Core.Shape) {

					// Ask by the StencilSet if the source, the edge and the
					// target valid connections.
					if (this.docker.parent instanceof ORYX.Core.Edge) {

						var highestParent = this
								.getHighestParentBeforeCanvas(uiObj);
						/*
						 * Ensure that the shape to dock is not a child shape of
						 * the same edge.
						 */
						if (highestParent instanceof ORYX.Core.Edge
								&& this.docker.parent === highestParent) {
							this.isValid = false;
							this.dockerParent._update();
							return;
						}
						this.isValid = false;
						var curObj = uiObj, orgObj = uiObj;
						while (!this.isValid && curObj
								&& !(curObj instanceof ORYX.Core.Canvas)) {
							uiObj = curObj;
							this.isValid = this.facade.getRules().canConnect({
								sourceShape : this.dockerSource ? // Is there
																	// a docked
																	// source
										this.dockerSource
										: // than set this
										(this.isStartDocker ? // if not and if
																// the Docker is
																// the start
																// docker
												uiObj
												: // take the last uiObj
												undefined), // if not set it to
															// undefined;
								edgeShape : this.docker.parent,
								targetShape : this.dockerTarget ? // Is there
																	// a docked
																	// target
										this.dockerTarget
										: // than set this
										(this.isEndDocker ? // if not and if the
															// Docker is not the
															// start docker
												uiObj
												: // take the last uiObj
												undefined)
									// if not set it to undefined;
								});
							curObj = curObj.parent;
						}

						// Reset uiObj if no
						// valid parent is found
						if (!this.isValid) {
							uiObj = orgObj;
						}

					} else {
						this.isValid = this.facade.getRules().canConnect({
									sourceShape : uiObj,
									edgeShape : this.docker.parent,
									targetShape : this.docker.parent
								});
					}

					// If there is a lastUIObj, hide the magnets
					if (this.lastUIObj) {
						this.hideMagnets(this.lastUIObj);
					}

					// If there is a valid connection, show the magnets
					if (this.isValid) {
						this.showMagnets(uiObj);
					}

					// Set the Highlight Rectangle by these value
					this.showHighlight(uiObj, this.isValid
									? this.VALIDCOLOR
									: this.INVALIDCOLOR);

					// Buffer the current Shape
					this.lastUIObj = uiObj;
				} else {
					// If there is no top level Shape, then hide the highligting
					// of the last Shape
					this.hideHighlight();
					this.lastUIObj ? this.hideMagnets(this.lastUIObj) : null;
					this.lastUIObj = undefined;
					this.isValid = false;
				}

				// Snap to the nearest Magnet
				if (this.lastUIObj && this.isValid
						&& !(event.shiftKey || event.ctrlKey)) {
					snapToMagnet = this.lastUIObj.magnets.find(
							function(magnet) {
								return magnet.absoluteBounds()
										.isIncluded(evPos);
							});

					if (snapToMagnet) {
						this.docker.bounds.centerMoveTo(snapToMagnet
								.absoluteCenterXY());
						// this.docker.update()
					}
				}
			}
		}
		// Snap to on the nearest Docker of the same parent
		if (!(event.shiftKey || event.ctrlKey) && !snapToMagnet) {
			var minOffset = ORYX.CONFIG.DOCKER_SNAP_OFFSET;
			var nearestX = minOffset + 1;
			var nearestY = minOffset + 1;

			var dockerCenter = this.docker.bounds.center();

			if (this.docker.parent) {

				this.docker.parent.dockers.each((function(docker) {
							if (this.docker == docker) {
								return
							};

							var center = docker.referencePoint
									? docker.getAbsoluteReferencePoint()
									: docker.bounds.center();

							nearestX = Math.abs(nearestX) > Math.abs(center.x
									- dockerCenter.x) ? center.x
									- dockerCenter.x : nearestX;
							nearestY = Math.abs(nearestY) > Math.abs(center.y
									- dockerCenter.y) ? center.y
									- dockerCenter.y : nearestY;

						}).bind(this));

				if (Math.abs(nearestX) < minOffset
						|| Math.abs(nearestY) < minOffset) {
					nearestX = Math.abs(nearestX) < minOffset ? nearestX : 0;
					nearestY = Math.abs(nearestY) < minOffset ? nearestY : 0;

					this.docker.bounds.centerMoveTo(dockerCenter.x + nearestX,
							dockerCenter.y + nearestY);
					// this.docker.update()
				} else {

					var previous = this.docker.parent.dockers[Math
							.max(	this.docker.parent.dockers
											.indexOf(this.docker)
											- 1, 0)];
					var next = this.docker.parent.dockers[Math
							.min(	this.docker.parent.dockers
											.indexOf(this.docker)
											+ 1,
									this.docker.parent.dockers.length - 1)];

					if (previous && next && previous !== this.docker
							&& next !== this.docker) {
						var cp = previous.bounds.center();
						var cn = next.bounds.center();
						var cd = this.docker.bounds.center();

						// Checks if the point is on the line between previous
						// and next
						if (ORYX.Core.Math.isPointInLine(cd.x, cd.y, cp.x,
								cp.y, cn.x, cn.y, 10)) {
							// Get the rise
							var raise = (Number(cn.y) - Number(cp.y))
									/ (Number(cn.x) - Number(cp.x));
							// Calculate the intersection point
							var intersecX = ((cp.y - (cp.x * raise)) - (cd.y - (cd.x * (-Math
									.pow(raise, -1)))))
									/ ((-Math.pow(raise, -1)) - raise);
							var intersecY = (cp.y - (cp.x * raise))
									+ (raise * intersecX);

							if (isNaN(intersecX) || isNaN(intersecY)) {
								return;
							}

							this.docker.bounds.centerMoveTo(intersecX,
									intersecY);
						}
					}

				}
			}
		}
		// this.facade.getCanvas().update();
		this.dockerParent._update();
	},

	/**
	 * Docker MouseUp Handler
	 * 
	 */
	dockerMovedFinished : function(event) {

		/* Reset to buffered shape selection */
		this.facade.setSelection(this.shapeSelection);

		// Hide the border
		this.hideHighlight();

		// Show all Labels from Docker
		this.dockerParent.getLabels().each(function(label) {
			label.show();
				// label.update();
			});

		// If there is a last top level Shape
		if (this.lastUIObj && (this.isStartDocker || this.isEndDocker)) {
			// If there is a valid connection, the set as a docked Shape to them
			if (this.isValid) {

				this.docker.setDockedShape(this.lastUIObj);

				this.facade.raiseEvent({
							type : ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED,
							docker : this.docker,
							parent : this.docker.parent,
							target : this.lastUIObj
						});
			}

			this.hideMagnets(this.lastUIObj);
		}

		// Hide the Docker
		this.docker.hide();

		if (this.outerDockerNotMoved) {
			// Get the EventPosition and all Shapes on these point
			var evPos = this.facade.eventCoordinates(event);
			var shapes = this.facade.getCanvas()
					.getAbstractShapesAtPosition(evPos);

			/* Remove edges from selection */
			var shapeWithoutEdges = shapes.findAll(function(node) {
						return node instanceof ORYX.Core.Node;
					});
			shapes = shapeWithoutEdges.length ? shapeWithoutEdges : shapes;
			this.facade.setSelection(shapes);
		} else {
			// Command-Pattern for dragging one docker
			var dragDockerCommand = ORYX.Core.Command.extend({
						construct : function(docker, newPos, oldPos,
								newDockedShape, oldDockedShape, facade) {
							this.docker = docker;
							this.index = docker.parent.dockers.indexOf(docker);
							this.newPosition = newPos;
							this.newDockedShape = newDockedShape;
							this.oldPosition = oldPos;
							this.oldDockedShape = oldDockedShape;
							this.facade = facade;
							this.index = docker.parent.dockers.indexOf(docker);
							this.shape = docker.parent;

						},
						execute : function() {
							if (!this.docker.parent) {
								this.docker = this.shape.dockers[this.index];
							}
							this.dock(this.newDockedShape, this.newPosition);
							this.removedDockers = this.shape
									.removeUnusedDockers();
							this.facade.updateSelection();
						},
						rollback : function() {
							this.dock(this.oldDockedShape, this.oldPosition);
							(this.removedDockers || $H({})).each(function(d) {
										this.shape.add(d.value, Number(d.key));
										this.shape._update(true);
									}.bind(this));
							this.facade.updateSelection();
						},
						dock : function(toDockShape, pos) {
							// Set the Docker to the new Shape
							this.docker.setDockedShape(undefined);
							if (toDockShape) {
								this.docker.setDockedShape(toDockShape);
								this.docker.setReferencePoint(pos);
								// this.docker.update();
								// this.docker.parent._update();
							} else {
								this.docker.bounds.centerMoveTo(pos);
							}

							this.facade.getCanvas().update();
						}
					});

			if (this.docker.parent) {
				// Instanziate the dockCommand
				var command = new dragDockerCommand(this.docker, this.docker
								.getDockedShape()
								? this.docker.referencePoint
								: this.docker.bounds.center(),
						this._commandArg.refPoint,
						this.docker.getDockedShape(),
						this._commandArg.dockedShape, this.facade);
				this.facade.executeCommands([command]);
			}
		}

		// Update all Shapes
		// this.facade.updateSelection();

		// Undefined all variables
		this.docker = undefined;
		this.dockerParent = undefined;
		this.dockerSource = undefined;
		this.dockerTarget = undefined;
		this.lastUIObj = undefined;
	},

	/**
	 * Hide the highlighting
	 */
	hideHighlight : function() {
		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
					highlightId : 'validDockedShape'
				});
	},

	/**
	 * Show the highlighting
	 * 
	 */
	showHighlight : function(uiObj, color) {

		this.facade.raiseEvent({
					type : ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
					highlightId : 'validDockedShape',
					elements : [uiObj],
					color : color
				});
	},

	showMagnets : function(uiObj) {
		uiObj.magnets.each(function(magnet) {
					magnet.show();
				});
	},

	hideMagnets : function(uiObj) {
		uiObj.magnets.each(function(magnet) {
					magnet.hide();
				});
	},

	getHighestParentBeforeCanvas : function(shape) {
		if (!(shape instanceof ORYX.Core.Shape)) {
			return undefined;
		}

		var parent = shape.parent;
		while (parent && !(parent.parent instanceof ORYX.Core.Canvas)) {
			parent = parent.parent;
		}

		return parent;
	}

});

/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.AddDocker = Clazz.extend({

	/**
	 * Constructor
	 * 
	 * @param {Object}
	 *            Facade: The Facade of the Editor
	 */
	construct : function(facade) {
		this.facade = facade;
		this.enableAdd = false;
		this.enableRemove = false;

		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN,
				this.handleMouseDown.bind(this));
	},

	setEnableAdd : function(enable) {
		this.enableAdd = enable;

		if (this.enableAdd) {
			jQuery("#add-bendpoint-button").addClass('pressed');
		} else {
			jQuery("#add-bendpoint-button").removeClass('pressed');
			jQuery("#add-bendpoint-button").blur();
		}
	},
	setEnableRemove : function(enable) {
		this.enableRemove = enable;

		if (this.enableRemove) {
			jQuery("#remove-bendpoint-button").addClass('pressed');
		} else {
			jQuery("#remove-bendpoint-button").removeClass('pressed');
			jQuery("#remove-bendpoint-button").blur();
		}
	},

	enabledAdd : function(enable) {
		return this.enableAdd;
	},
	enabledRemove : function() {
		return this.enableRemove;
	},

	/**
	 * MouseDown Handler
	 * 
	 */
	handleMouseDown : function(event, uiObj) {
		if (this.enabledAdd() && uiObj instanceof ORYX.Core.Edge) {
			this.newDockerCommand({
						edge : uiObj,
						position : this.facade.eventCoordinates(event)
					});
			this.setEnableAdd(false);

		} else if (this.enabledRemove()
				&& uiObj instanceof ORYX.Core.Controls.Docker
				&& uiObj.parent instanceof ORYX.Core.Edge) {
			this.newDockerCommand({
						edge : uiObj.parent,
						docker : uiObj
					});
			this.setEnableRemove(false);
		}
		document.body.style.cursor = 'default';
	},

	// Options: edge (required), position (required if add), docker (required if
	// delete)
	newDockerCommand : function(options) {
		if (!options.edge)
			return;

		var commandClass = ORYX.Core.Command.extend({
					construct : function(addEnabled, deleteEnabled, edge,
							docker, pos, facade) {
						this.addEnabled = addEnabled;
						this.deleteEnabled = deleteEnabled;
						this.edge = edge;
						this.docker = docker;
						this.pos = pos;
						this.facade = facade;
					},
					execute : function() {
						if (this.addEnabled) {
							if (!this.docker) {
								this.docker = this.edge.addDocker(this.pos);
								this.index = this.edge.dockers
										.indexOf(this.docker);
							} else {
								this.edge.add(this.docker, this.index);
							}
						} else if (this.deleteEnabled) {
							this.index = this.edge.dockers.indexOf(this.docker);
							this.pos = this.docker.bounds.center();
							this.edge.removeDocker(this.docker);
						}
						this.edge.getLabels().invoke("show");
						this.facade.getCanvas().update();
						this.facade.updateSelection();
					},
					rollback : function() {
						if (this.addEnabled) {
							if (this.docker instanceof ORYX.Core.Controls.Docker) {
								this.edge.removeDocker(this.docker);
							}
						} else if (this.deleteEnabled) {
							this.edge.add(this.docker, this.index);
						}
						this.edge.getLabels().invoke("show");
						this.facade.getCanvas().update();
						this.facade.updateSelection();
					}
				})

		var command = new commandClass(this.enabledAdd(), this.enabledRemove(),
				options.edge, options.docker, options.position, this.facade);

		this.facade.executeCommands([command]);
	}
});

/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.SelectionFrame = Clazz.extend({

	construct : function(facade) {
		this.facade = facade;

		// Register on MouseEvents
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN,
				this.handleMouseDown.bind(this));
		document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP,
				this.handleMouseUp.bind(this), true);

		// Some initiale variables
		this.position = {
			x : 0,
			y : 0
		};
		this.size = {
			width : 0,
			height : 0
		};
		this.offsetPosition = {
			x : 0,
			y : 0
		};

		// (Un)Register Mouse-Move Event
		this.moveCallback = undefined;
		this.offsetScroll = {
			x : 0,
			y : 0
		};
		// HTML-Node of Selection-Frame
		this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml",
				$('canvasSection'), ['div', {
							'class' : 'Oryx_SelectionFrame'
						}]);

		this.hide();
	},

	handleMouseDown : function(event, uiObj) {
		// If there is the Canvas
		if (uiObj instanceof ORYX.Core.Canvas) {
			// Calculate the Offset
			var scrollNode = uiObj.rootNode.parentNode.parentNode;

			var a = this.facade.getCanvas().node.getScreenCTM();
			this.offsetPosition = {
				x : a.e,
				y : a.f
			};

			// Set the new Position
			this.setPos({
						x : Event.pointerX(event)
								- jQuery("#canvasSection").offset().left,
						y : Event.pointerY(event)
								- jQuery("#canvasSection").offset().top + 5
					});

			// Reset the size
			this.resize({
						width : 0,
						height : 0
					});
			this.moveCallback = this.handleMouseMove.bind(this);

			// Register Mouse-Move Event
			document.documentElement.addEventListener(
					ORYX.CONFIG.EVENT_MOUSEMOVE, this.moveCallback, false);

			this.offsetScroll = {
				x : scrollNode.scrollLeft,
				y : scrollNode.scrollTop
			};

			// Show the Frame
			this.show();
		}

		Event.stop(event);
	},

	handleMouseUp : function(event) {
		// If there was an MouseMoving
		if (this.moveCallback) {
			// Hide the Frame
			this.hide();

			// Unregister Mouse-Move
			document.documentElement.removeEventListener(
					ORYX.CONFIG.EVENT_MOUSEMOVE, this.moveCallback, false);

			this.moveCallback = undefined;

			var corrSVG = this.facade.getCanvas().node.getScreenCTM();

			// Calculate the positions of the Frame
			var a = {
				x : this.size.width > 0 ? this.position.x : this.position.x
						+ this.size.width,
				y : this.size.height > 0 ? this.position.y : this.position.y
						+ this.size.height
			};

			var b = {
				x : a.x + Math.abs(this.size.width),
				y : a.y + Math.abs(this.size.height)
			};

			var additionalIEZoom = 1;
			if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
				var ua = navigator.userAgent;
				if (ua.indexOf('MSIE') >= 0) {
					// IE 10 and below
					var zoom = Math
							.round((screen.deviceXDPI / screen.logicalXDPI)
									* 100);
					if (zoom !== 100) {
						additionalIEZoom = zoom / 100
					}
				}
			}

			if (additionalIEZoom === 1) {
				a.x = a.x
						- (corrSVG.e - jQuery("#canvasSection").offset().left);
				a.y = a.y - (corrSVG.f - jQuery("#canvasSection").offset().top);
				b.x = b.x
						- (corrSVG.e - jQuery("#canvasSection").offset().left);
				b.y = b.y - (corrSVG.f - jQuery("#canvasSection").offset().top);

			} else {
				var canvasOffsetLeft = jQuery("#canvasSection").offset().left;
				var canvasScrollLeft = jQuery("#canvasSection").scrollLeft();
				var canvasScrollTop = jQuery("#canvasSection").scrollTop();

				var offset = a.e - (canvasOffsetLeft * additionalIEZoom);
				var additionaloffset = 0;
				if (offset > 10) {
					additionaloffset = (offset / additionalIEZoom) - offset;
				}

				a.x = a.x
						- (corrSVG.e - (canvasOffsetLeft * additionalIEZoom)
								+ additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft));
				a.y = a.y
						- (corrSVG.f
								- (jQuery("#canvasSection").offset().top * additionalIEZoom) + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop));
				b.x = b.x
						- (corrSVG.e - (canvasOffsetLeft * additionalIEZoom)
								+ additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft));
				b.y = b.y
						- (corrSVG.f
								- (jQuery("#canvasSection").offset().top * additionalIEZoom) + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop));
			}

			// Fit to SVG-Coordinates
			a.x /= corrSVG.a;
			a.y /= corrSVG.d;
			b.x /= corrSVG.a;
			b.y /= corrSVG.d;

			// Calculate the elements from the childs of the canvas
			var elements = this.facade.getCanvas().getChildShapes(true)
					.findAll(function(value) {
						var absBounds = value.absoluteBounds();

						var bA = absBounds.upperLeft();
						var bB = absBounds.lowerRight();

						if (bA.x > a.x && bA.y > a.y && bB.x < b.x
								&& bB.y < b.y)
							return true;
						return false;
					});

			// Set the selection
			this.facade.setSelection(elements);
		}
	},

	handleMouseMove : function(event) {
		// Calculate the size
		var size = {
			width : Event.pointerX(event) - this.position.x
					- jQuery("#canvasSection").offset().left,
			height : Event.pointerY(event) - this.position.y
					- jQuery("#canvasSection").offset().top + 5
		};

		var scrollNode = this.facade.getCanvas().rootNode.parentNode.parentNode;
		size.width -= this.offsetScroll.x - scrollNode.scrollLeft;
		size.height -= this.offsetScroll.y - scrollNode.scrollTop;

		// Set the size
		this.resize(size);

		Event.stop(event);
	},

	hide : function() {
		this.node.style.display = "none";
	},

	show : function() {
		this.node.style.display = "";
	},

	setPos : function(pos) {
		// Set the Position
		this.node.style.top = pos.y + "px";
		this.node.style.left = pos.x + "px";
		this.position = pos;
	},

	resize : function(size) {

		// Calculate the negative offset
		this.setPos(this.position);
		this.size = Object.clone(size);

		if (size.width < 0) {
			this.node.style.left = (this.position.x + size.width) + "px";
			size.width = -size.width;
		}
		if (size.height < 0) {
			this.node.style.top = (this.position.y + size.height) + "px";
			size.height = -size.height;
		}

		// Set the size
		this.node.style.width = size.width + "px";
		this.node.style.height = size.height + "px";
	}

});

/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.ShapeHighlighting = Clazz.extend({

	construct : function(facade) {

		this.parentNode = facade.getCanvas().getSvgContainer();

		// The parent Node
		this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
				this.parentNode, ['g']);

		this.highlightNodes = {};

		facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
				this.setHighlight.bind(this));
		facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
				this.hideHighlight.bind(this));

	},

	setHighlight : function(options) {
		if (options && options.highlightId) {
			var node = this.highlightNodes[options.highlightId];

			if (!node) {
				node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
						this.node, ['path', {
									"stroke-width" : 2.0,
									"fill" : "none"
								}]);

				this.highlightNodes[options.highlightId] = node;
			}

			if (options.elements && options.elements.length > 0) {

				this.setAttributesByStyle(node, options);
				this.show(node);

			} else {

				this.hide(node);

			}

		}
	},

	hideHighlight : function(options) {
		if (options && options.highlightId
				&& this.highlightNodes[options.highlightId]) {
			this.hide(this.highlightNodes[options.highlightId]);
		}
	},

	hide : function(node) {
		node.setAttributeNS(null, 'display', 'none');
	},

	show : function(node) {
		node.setAttributeNS(null, 'display', '');
	},

	setAttributesByStyle : function(node, options) {

		// If the style say, that it should look like a rectangle
		if (options.style
				&& options.style == ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE) {

			// Set like this
			var bo = options.elements[0].absoluteBounds();

			var strWidth = options.strokewidth
					? options.strokewidth
					: ORYX.CONFIG.BORDER_OFFSET

			node.setAttributeNS(null, "d", this.getPathRectangle(bo.a, bo.b,
							strWidth));
			node.setAttributeNS(null, "stroke", options.color
							? options.color
							: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
			node.setAttributeNS(null, "stroke-opacity", options.opacity
							? options.opacity
							: 0.2);
			node.setAttributeNS(null, "stroke-width", strWidth);

		} else if (options.elements.length == 1
				&& options.elements[0] instanceof ORYX.Core.Edge
				&& options.highlightId != "selection") {

			/* Highlight containment of edge's childs */
			var path = this.getPathEdge(options.elements[0].dockers);
			if (path && path.length > 0) {
				node.setAttributeNS(null, "d", path);
			}
			node.setAttributeNS(null, "stroke", options.color
							? options.color
							: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
			node.setAttributeNS(null, "stroke-opacity", options.opacity
							? options.opacity
							: 0.2);
			node.setAttributeNS(null, "stroke-width",
					ORYX.CONFIG.OFFSET_EDGE_BOUNDS);

		} else {
			// If not, set just the corners
			var path = this.getPathByElements(options.elements);
			if (path && path.length > 0) {
				node.setAttributeNS(null, "d", path);
			}
			node.setAttributeNS(null, "stroke", options.color
							? options.color
							: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
			node.setAttributeNS(null, "stroke-opacity", options.opacity
							? options.opacity
							: 1.0);
			node.setAttributeNS(null, "stroke-width", options.strokewidth
							? options.strokewidth
							: 2.0);

		}
	},

	getPathByElements : function(elements) {
		if (!elements || elements.length <= 0) {
			return undefined
		}

		// Get the padding and the size
		var padding = ORYX.CONFIG.SELECTED_AREA_PADDING;

		var path = ""

		// Get thru all Elements
		elements.each((function(element) {
					if (!element) {
						return
					}
					// Get the absolute Bounds and the two Points
					var bounds = element.absoluteBounds();
					bounds.widen(padding)
					var a = bounds.upperLeft();
					var b = bounds.lowerRight();

					path = path + this.getPath(a, b);

				}).bind(this));

		return path;

	},

	getPath : function(a, b) {

		return this.getPathCorners(a, b);

	},

	getPathCorners : function(a, b) {

		var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE;

		var path = ""

		// Set: Upper left
		path = path + "M" + a.x + " " + (a.y + size) + " l0 -" + size + " l"
				+ size + " 0 ";
		// Set: Lower left
		path = path + "M" + a.x + " " + (b.y - size) + " l0 " + size + " l"
				+ size + " 0 ";
		// Set: Lower right
		path = path + "M" + b.x + " " + (b.y - size) + " l0 " + size + " l-"
				+ size + " 0 ";
		// Set: Upper right
		path = path + "M" + b.x + " " + (a.y + size) + " l0 -" + size + " l-"
				+ size + " 0 ";

		return path;
	},

	getPathRectangle : function(a, b, strokeWidth) {

		var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE;

		var path = ""
		var offset = strokeWidth / 2.0;

		// Set: Upper left
		path = path + "M" + (a.x + offset) + " " + (a.y);
		path = path + " L" + (a.x + offset) + " " + (b.y - offset);
		path = path + " L" + (b.x - offset) + " " + (b.y - offset);
		path = path + " L" + (b.x - offset) + " " + (a.y + offset);
		path = path + " L" + (a.x + offset) + " " + (a.y + offset);

		return path;
	},

	getPathEdge : function(edgeDockers) {
		var length = edgeDockers.length;
		var path = "M" + edgeDockers[0].bounds.center().x + " "
				+ edgeDockers[0].bounds.center().y;

		for (i = 1; i < length; i++) {
			var dockerPoint = edgeDockers[i].bounds.center();
			path = path + " L" + dockerPoint.x + " " + dockerPoint.y;
		}

		return path;
	}

});

ORYX.Plugins.HighlightingSelectedShapes = Clazz.extend({

			construct : function(facade) {
				this.facade = facade;
				this.opacityFull = 0.9;
				this.opacityLow = 0.4;

				// Register on Dragging-Events for show/hide of ShapeMenu
				// this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_START,
				// this.hide.bind(this));
				// this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_END,
				// this.show.bind(this));
			},

			/**
			 * On the Selection-Changed
			 * 
			 */
			onSelectionChanged : function(event) {
				if (event.elements && event.elements.length > 1) {
					this.facade.raiseEvent({
								type : ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
								highlightId : 'selection',
								elements : event.elements
										.without(event.subSelection),
								color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR,
								opacity : !event.subSelection
										? this.opacityFull
										: this.opacityLow
							});

					if (event.subSelection) {
						this.facade.raiseEvent({
									type : ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
									highlightId : 'subselection',
									elements : [event.subSelection],
									color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR,
									opacity : this.opacityFull
								});
					} else {
						this.facade.raiseEvent({
									type : ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
									highlightId : 'subselection'
								});
					}

				} else {
					this.facade.raiseEvent({
								type : ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
								highlightId : 'selection'
							});
					this.facade.raiseEvent({
								type : ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
								highlightId : 'subselection'
							});
				}
			}
		});/*
			 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
			 * License rights for this program may be obtained from Alfresco
			 * Software, Ltd. pursuant to a written agreement and any use of
			 * this program without such an agreement is prohibited.
			 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.Overlay = Clazz.extend({

	facade : undefined,

	styleNode : undefined,

	construct : function(facade) {

		this.facade = facade;

		this.changes = [];

		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_OVERLAY_SHOW, this.show
						.bind(this));
		this.facade.registerOnEvent(ORYX.CONFIG.EVENT_OVERLAY_HIDE, this.hide
						.bind(this));

		this.styleNode = document.createElement('style')
		this.styleNode.setAttributeNS(null, 'type', 'text/css')

		document.getElementsByTagName('head')[0].appendChild(this.styleNode)

	},

	/**
	 * Show the overlay for specific nodes
	 * 
	 * @param {Object}
	 *            options
	 * 
	 * String options.id - MUST - Define the id of the overlay (is needed for
	 * the hiding of this overlay) ORYX.Core.Shape[] options.shapes - MUST -
	 * Define the Shapes for the changes attr-name:value options.changes -
	 * Defines all the changes which should be shown
	 * 
	 * 
	 */
	show : function(options) {

		// Checks if all arguments are available
		if (!options || !options.shapes || !options.shapes instanceof Array
				|| !options.id || !options.id instanceof String
				|| options.id.length == 0) {

			return

		}

		// if( this.changes[options.id]){
		// this.hide( options )
		// }

		// Checked if attributes are setted
		if (options.attributes) {

			// FOR EACH - Shape
			options.shapes.each(function(el) {

						// Checks if the node is a Shape
						if (!el instanceof ORYX.Core.Shape) {
							return
						}

						this.setAttributes(el.node, options.attributes)

					}.bind(this))

		}

		var isSVG = true
		try {
			isSVG = options.node && options.node instanceof SVGElement;
		} catch (e) {
		}

		// Checks if node is setted and if this is an SVGElement
		if (options.node && isSVG) {

			options["_temps"] = []

			// FOR EACH - Node
			options.shapes.each(function(el, index) {

						// Checks if the node is a Shape
						if (!el instanceof ORYX.Core.Shape) {
							return
						}

						var _temp = {}
						_temp.svg = options.dontCloneNode
								? options.node
								: options.node.cloneNode(true);

						// Add the svg node to the ORYX-Shape
						el.node.firstChild.appendChild(_temp.svg)

						// If
						if (el instanceof ORYX.Core.Edge
								&& !options.nodePosition) {
							options['nodePosition'] = "START"
						}

						// If the node position is setted, it has to be
						// transformed
						if (options.nodePosition) {

							var b = el.bounds;
							var p = options.nodePosition.toUpperCase();

							// Check the values of START and END
							if (el instanceof ORYX.Core.Node && p == "START") {
								p = "NW";
							} else if (el instanceof ORYX.Core.Node
									&& p == "END") {
								p = "SE";
							} else if (el instanceof ORYX.Core.Edge
									&& p == "START") {
								b = el.getDockers().first().bounds
							} else if (el instanceof ORYX.Core.Edge
									&& p == "END") {
								b = el.getDockers().last().bounds
							}

							// Create a callback for the changing the position
							// depending on the position string
							_temp.callback = function() {

								var x = 0;
								var y = 0;

								if (p == "NW") {
									// Do Nothing
								} else if (p == "N") {
									x = b.width() / 2;
								} else if (p == "NE") {
									x = b.width();
								} else if (p == "E") {
									x = b.width();
									y = b.height() / 2;
								} else if (p == "SE") {
									x = b.width();
									y = b.height();
								} else if (p == "S") {
									x = b.width() / 2;
									y = b.height();
								} else if (p == "SW") {
									y = b.height();
								} else if (p == "W") {
									y = b.height() / 2;
								} else if (p == "START" || p == "END") {
									x = b.width() / 2;
									y = b.height() / 2;
								} else {
									return
								}

								if (el instanceof ORYX.Core.Edge) {
									x += b.upperLeft().x;
									y += b.upperLeft().y;
								}

								_temp.svg.setAttributeNS(null, "transform",
										"translate(" + x + ", " + y + ")")

							}.bind(this)

							_temp.element = el;
							_temp.callback();

							b.registerCallback(_temp.callback);

						}

						options._temps.push(_temp)

					}.bind(this))

		}

		// Store the changes
		if (!this.changes[options.id]) {
			this.changes[options.id] = [];
		}

		this.changes[options.id].push(options);

	},

	/**
	 * Hide the overlay with the spefic id
	 * 
	 * @param {Object}
	 *            options
	 */
	hide : function(options) {

		// Checks if all arguments are available
		if (!options || !options.id || !options.id instanceof String
				|| options.id.length == 0 || !this.changes[options.id]) {

			return

		}

		// Delete all added attributes
		// FOR EACH - Shape
		this.changes[options.id].each(function(option) {

					option.shapes.each(function(el, index) {

								// Checks if the node is a Shape
								if (!el instanceof ORYX.Core.Shape) {
									return
								}

								this.deleteAttributes(el.node)

							}.bind(this));

					if (option._temps) {

						option._temps.each(function(tmp) {
									// Delete the added Node, if there is one
									if (tmp.svg && tmp.svg.parentNode) {
										tmp.svg.parentNode.removeChild(tmp.svg)
									}

									// If
									if (tmp.callback && tmp.element) {
										// It has to be unregistered from the
										// edge
										tmp.element.bounds
												.unregisterCallback(tmp.callback)
									}

								}.bind(this))

					}

				}.bind(this));

		this.changes[options.id] = null;

	},

	/**
	 * Set the given css attributes to that node
	 * 
	 * @param {HTMLElement}
	 *            node
	 * @param {Object}
	 *            attributes
	 */
	setAttributes : function(node, attributes) {

		// Get all the childs from ME
		var childs = this.getAllChilds(node.firstChild.firstChild)

		var ids = []

		// Add all Attributes which have relation to another node in this
		// document and concate the pure id out of it
		// This is for example important for the markers of a edge
		childs.each(function(e) {
					ids.push($A(e.attributes).findAll(function(attr) {
								return attr.nodeValue.startsWith('url(#')
							}))
				})
		ids = ids.flatten().compact();
		ids = ids.collect(function(s) {
					return s.nodeValue
				}).uniq();
		ids = ids.collect(function(s) {
					return s.slice(5, s.length - 1)
				})

		// Add the node ID to the id
		ids.unshift(node.id + ' .me')

		var attr = $H(attributes);
		var attrValue = attr.toJSON().gsub(',', ';').gsub('"', '');
		var attrMarkerValue = attributes.stroke ? attrValue.slice(0,
				attrValue.length - 1)
				+ "; fill:" + attributes.stroke + ";}" : attrValue;
		var attrTextValue;
		if (attributes.fill) {
			var copyAttr = Object.clone(attributes);
			copyAttr.fill = "black";
			attrTextValue = $H(copyAttr).toJSON().gsub(',', ';').gsub('"', '');
		}

		// Create the CSS-Tags Style out of the ids and the attributes
		csstags = ids.collect(function(s, i) {
					return "#"
							+ s
							+ " * "
							+ (!i ? attrValue : attrMarkerValue)
							+ ""
							+ (attrTextValue ? " #" + s + " text * "
									+ attrTextValue : "")
				})

		// Join all the tags
		var s = csstags.join(" ") + "\n"

		// And add to the end of the style tag
		this.styleNode.appendChild(document.createTextNode(s));

	},

	/**
	 * Deletes all attributes which are added in a special style sheet for that
	 * node
	 * 
	 * @param {HTMLElement}
	 *            node
	 */
	deleteAttributes : function(node) {

		// Get all children which contains the node id
		var delEl = $A(this.styleNode.childNodes).findAll(function(e) {
					return e.textContent.include('#' + node.id)
				});

		// Remove all of them
		delEl.each(function(el) {
					el.parentNode.removeChild(el);
				});
	},

	getAllChilds : function(node) {

		var childs = $A(node.childNodes)

		$A(node.childNodes).each(function(e) {
					childs.push(this.getAllChilds(e))
				}.bind(this))

		return childs.flatten();
	}

});
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

ORYX.Plugins.KeysMove = ORYX.Plugins.AbstractPlugin.extend({

	facade : undefined,

	construct : function(facade) {

		this.facade = facade;
		this.copyElements = [];

		// this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN,
		// this.keyHandler.bind(this));

		// SELECT ALL
		this.facade.offer({
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : 65,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.selectAll.bind(this)
				});

		// MOVE LEFT SMALL
		this.facade.offer({
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : ORYX.CONFIG.KEY_CODE_LEFT,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.move.bind(this,
							ORYX.CONFIG.KEY_CODE_LEFT, false)
				});

		// MOVE LEFT
		this.facade.offer({
					keyCodes : [{
								keyCode : ORYX.CONFIG.KEY_CODE_LEFT,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.move.bind(this,
							ORYX.CONFIG.KEY_CODE_LEFT, true)
				});

		// MOVE RIGHT SMALL
		this.facade.offer({
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : ORYX.CONFIG.KEY_CODE_RIGHT,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.move.bind(this,
							ORYX.CONFIG.KEY_CODE_RIGHT, false)
				});

		// MOVE RIGHT
		this.facade.offer({
					keyCodes : [{
								keyCode : ORYX.CONFIG.KEY_CODE_RIGHT,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.move.bind(this,
							ORYX.CONFIG.KEY_CODE_RIGHT, true)
				});

		// MOVE UP SMALL
		this.facade.offer({
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : ORYX.CONFIG.KEY_CODE_UP,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.move.bind(this,
							ORYX.CONFIG.KEY_CODE_UP, false)
				});

		// MOVE UP
		this.facade.offer({
					keyCodes : [{
								keyCode : ORYX.CONFIG.KEY_CODE_UP,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.move.bind(this,
							ORYX.CONFIG.KEY_CODE_UP, true)
				});

		// MOVE DOWN SMALL
		this.facade.offer({
					keyCodes : [{
								metaKeys : [ORYX.CONFIG.META_KEY_META_CTRL],
								keyCode : ORYX.CONFIG.KEY_CODE_DOWN,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.move.bind(this,
							ORYX.CONFIG.KEY_CODE_DOWN, false)
				});

		// MOVE DOWN
		this.facade.offer({
					keyCodes : [{
								keyCode : ORYX.CONFIG.KEY_CODE_DOWN,
								keyAction : ORYX.CONFIG.KEY_ACTION_DOWN
							}],
					functionality : this.move.bind(this,
							ORYX.CONFIG.KEY_CODE_DOWN, true)
				});

	},

	/**
	 * Select all shapes in the editor
	 * 
	 */
	selectAll : function(e) {
		Event.stop(e.event);
		this.facade.setSelection(this.facade.getCanvas().getChildShapes(true))
	},

	move : function(key, far, e) {

		Event.stop(e.event);

		// calculate the distance to move the objects and get the selection.
		var distance = far ? 20 : 5;
		var selection = this.facade.getSelection();
		var currentSelection = this.facade.getSelection();
		var p = {
			x : 0,
			y : 0
		};

		// switch on the key pressed and populate the point to move by.
		switch (key) {

			case ORYX.CONFIG.KEY_CODE_LEFT :
				p.x = -1 * distance;
				break;
			case ORYX.CONFIG.KEY_CODE_RIGHT :
				p.x = distance;
				break;
			case ORYX.CONFIG.KEY_CODE_UP :
				p.y = -1 * distance;
				break;
			case ORYX.CONFIG.KEY_CODE_DOWN :
				p.y = distance;
				break;
		}

		// move each shape in the selection by the point calculated and update
		// it.
		selection = selection.findAll(function(shape) {
					// Check if this shape is docked to an shape in the
					// selection
					if (shape instanceof ORYX.Core.Node
							&& shape.dockers.length == 1
							&& selection.include(shape.dockers.first()
									.getDockedShape())) {
						return false
					}

					// Check if any of the parent shape is included in the
					// selection
					var s = shape.parent;
					do {
						if (selection.include(s)) {
							return false
						}
					} while (s = s.parent);

					// Otherwise, return true
					return true;

				});

		/*
		 * Edges must not be movable, if only edges are selected and at least
		 * one of them is docked.
		 */
		var edgesMovable = true;
		var onlyEdgesSelected = selection.all(function(shape) {
					if (shape instanceof ORYX.Core.Edge) {
						if (shape.isDocked()) {
							edgesMovable = false;
						}
						return true;
					}
					return false;
				});

		if (onlyEdgesSelected && !edgesMovable) {
			/* Abort moving shapes */
			return;
		}

		selection = selection.map(function(shape) {
					if (shape instanceof ORYX.Core.Node) {
						/*
						 * if( shape.dockers.length == 1 ){ return
						 * shape.dockers.first() } else {
						 */
						return shape
						// }
					} else if (shape instanceof ORYX.Core.Edge) {

						var dockers = shape.dockers;

						if (selection.include(shape.dockers.first()
								.getDockedShape())) {
							dockers = dockers.without(shape.dockers.first())
						}

						if (selection.include(shape.dockers.last()
								.getDockedShape())) {
							dockers = dockers.without(shape.dockers.last())
						}

						return dockers

					} else {
						return null
					}

				}).flatten().compact();

		if (selection.size() > 0) {

			// Stop moving at canvas borders
			var selectionBounds = [
					this.facade.getCanvas().bounds.lowerRight().x,
					this.facade.getCanvas().bounds.lowerRight().y, 0, 0];
			selection.each(function(s) {
						selectionBounds[0] = Math.min(selectionBounds[0],
								s.bounds.upperLeft().x);
						selectionBounds[1] = Math.min(selectionBounds[1],
								s.bounds.upperLeft().y);
						selectionBounds[2] = Math.max(selectionBounds[2],
								s.bounds.lowerRight().x);
						selectionBounds[3] = Math.max(selectionBounds[3],
								s.bounds.lowerRight().y);
					});
			if (selectionBounds[0] + p.x < 0)
				p.x = -selectionBounds[0];
			if (selectionBounds[1] + p.y < 0)
				p.y = -selectionBounds[1];
			if (selectionBounds[2] + p.x > this.facade.getCanvas().bounds
					.lowerRight().x)
				p.x = this.facade.getCanvas().bounds.lowerRight().x
						- selectionBounds[2];
			if (selectionBounds[3] + p.y > this.facade.getCanvas().bounds
					.lowerRight().y)
				p.y = this.facade.getCanvas().bounds.lowerRight().y
						- selectionBounds[3];

			if (p.x != 0 || p.y != 0) {
				// Instantiate the moveCommand
				var commands = [new ORYX.Core.Command.Move(selection, p, null,
						currentSelection, this)];
				// Execute the commands
				this.facade.executeCommands(commands);
			}

		}
	},

	getUndockedCommant : function(shapes) {

		var undockEdgeCommand = ORYX.Core.Command.extend({
					construct : function(moveShapes) {
						this.dockers = moveShapes.collect(function(shape) {
							return shape instanceof ORYX.Core.Controls.Docker
									? {
										docker : shape,
										dockedShape : shape.getDockedShape(),
										refPoint : shape.referencePoint
									}
									: undefined
						}).compact();
					},
					execute : function() {
						this.dockers.each(function(el) {
									el.docker.setDockedShape(undefined);
								})
					},
					rollback : function() {
						this.dockers.each(function(el) {
							el.docker.setDockedShape(el.dockedShape);
							el.docker.setReferencePoint(el.refPoint);
								// el.docker.update();
							})
					}
				});

		command = new undockEdgeCommand(shapes);
		command.execute();
		return command;
	}
	,

		// /**
		// * The key handler for this plugin. Every action from the set of cut,
		// copy,
		// * paste and delete should be accessible trough simple keyboard
		// shortcuts.
		// * This method checks whether any event triggers one of those actions.
		// *
		// * @param {Object} event The keyboard event that should be analysed
		// for
		// * triggering of this plugin.
		// */
		// keyHandler: function(event){
		// //TODO document what event.which is.
		//        
		// ORYX.Log.debug("keysMove.js handles a keyEvent.");
		//        
		// // assure we have the current event.
		// if (!event)
		// event = window.event;
		//        
		// // get the currently pressed key and state of control key.
		// var pressedKey = event.which || event.keyCode;
		// var ctrlPressed = event.ctrlKey;
		//
		// // if the key is one of the arrow keys, forward to move and return.
		// if ([ORYX.CONFIG.KEY_CODE_LEFT, ORYX.CONFIG.KEY_CODE_RIGHT,
		// ORYX.CONFIG.KEY_CODE_UP,
		// ORYX.CONFIG.KEY_CODE_DOWN].include(pressedKey)) {
		//			
		// this.move(pressedKey, !ctrlPressed);
		// return;
		// }
		//		
		// }

	});
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins) {
	ORYX.Plugins = {}
}
if (!ORYX.Plugins.Layouter) {
	ORYX.Plugins.Layouter = {}
}

new function() {

	/**
	 * Edge layouter is an implementation to layout an edge
	 * 
	 * @class ORYX.Plugins.Layouter.EdgeLayouter
	 * @author Willi Tscheschner
	 */
	ORYX.Plugins.Layouter.EdgeLayouter = ORYX.Plugins.AbstractLayouter.extend({

		/**
		 * Layout only Edges
		 */
		layouted : [
				"http://b3mn.org/stencilset/bpmn1.1#SequenceFlow",
				"http://b3mn.org/stencilset/bpmn1.1#MessageFlow",
				"http://b3mn.org/stencilset/timjpdl3#SequenceFlow",
				"http://b3mn.org/stencilset/jbpm4#SequenceFlow",
				"http://b3mn.org/stencilset/bpmn2.0#MessageFlow",
				"http://b3mn.org/stencilset/bpmn2.0#SequenceFlow",
				"http://b3mn.org/stencilset/bpmn2.0choreography#MessageFlow",
				"http://b3mn.org/stencilset/bpmn2.0choreography#SequenceFlow",
				"http://b3mn.org/stencilset/bpmn2.0conversation#ConversationLink",
				"http://b3mn.org/stencilset/epc#ControlFlow",
				"http://www.signavio.com/stencilsets/processmap#ProcessLink",
				"http://www.signavio.com/stencilsets/organigram#connection"],

		/**
		 * Layout a set on edges
		 * 
		 * @param {Object}
		 *            edges
		 */
		layout : function(edges) {
			edges.each(function(edge) {
						this.doLayout(edge)
					}.bind(this))
		},

		/**
		 * Layout one edge
		 * 
		 * @param {Object}
		 *            edge
		 */
		doLayout : function(edge) {
			// Get from and to node
			var from = edge.getIncomingNodes()[0];
			var to = edge.getOutgoingNodes()[0];

			// Return if one is null
			if (!from || !to) {
				return
			}

			var positions = this.getPositions(from, to, edge);

			if (positions.length > 0) {
				this.setDockers(edge, positions[0].a, positions[0].b);
			}

		},

		/**
		 * Returns a set on positions which are not containt either in the
		 * bounds in from or to.
		 * 
		 * @param {Object}
		 *            from Shape where the edge is come from
		 * @param {Object}
		 *            to Shape where the edge is leading to
		 * @param {Object}
		 *            edge Edge between from and to
		 */
		getPositions : function(from, to, edge) {

			// Get absolute bounds
			var ab = from.absoluteBounds();
			var bb = to.absoluteBounds();

			// Get center from and to
			var a = ab.center();
			var b = bb.center();

			var am = ab.midPoint();
			var bm = bb.midPoint();

			// Get first and last reference point
			var first = Object.clone(edge.dockers.first().referencePoint);
			var last = Object.clone(edge.dockers.last().referencePoint);
			// Get the absolute one
			var aFirst = edge.dockers.first().getAbsoluteReferencePoint();
			var aLast = edge.dockers.last().getAbsoluteReferencePoint();

			// IF ------>
			// or |
			// V
			// Do nothing
			if (Math.abs(aFirst.x - aLast.x) < 1
					|| Math.abs(aFirst.y - aLast.y) < 1) {
				return []
			}

			// Calc center position, between a and b
			// depending on there weight
			var m = {}
			m.x = a.x < b.x
					? (((b.x - bb.width() / 2) - (a.x + ab.width() / 2)) / 2)
							+ (a.x + ab.width() / 2)
					: (((a.x - ab.width() / 2) - (b.x + bb.width() / 2)) / 2)
							+ (b.x + bb.width() / 2);

			m.y = a.y < b.y
					? (((b.y - bb.height() / 2) - (a.y + ab.height() / 2)) / 2)
							+ (a.y + ab.height() / 2)
					: (((a.y - ab.height() / 2) - (b.y + bb.height() / 2)) / 2)
							+ (b.y + bb.height() / 2);

			// Enlarge both bounds with 10
			ab.widen(5); // Wide the from less than
			bb.widen(20);// the to because of the arrow from the edge

			var positions = [];
			var off = this.getOffset.bind(this);

			// Checks ----+
			// |
			// V
			if (!ab.isIncluded(b.x, a.y) && !bb.isIncluded(b.x, a.y)) {
				positions.push({
							a : {
								x : b.x + off(last, bm, "x"),
								y : a.y + off(first, am, "y")
							},
							z : this.getWeight(from, a.x < b.x ? "r" : "l", to,
									a.y < b.y ? "t" : "b", edge)
						});
			}

			// Checks |
			// +--->
			if (!ab.isIncluded(a.x, b.y) && !bb.isIncluded(a.x, b.y)) {
				positions.push({
							a : {
								x : a.x + off(first, am, "x"),
								y : b.y + off(last, bm, "y")
							},
							z : this.getWeight(from, a.y < b.y ? "b" : "t", to,
									a.x < b.x ? "l" : "r", edge)
						});
			}

			// Checks --+
			// |
			// +--->
			if (!ab.isIncluded(m.x, a.y) && !bb.isIncluded(m.x, b.y)) {
				positions.push({
							a : {
								x : m.x,
								y : a.y + off(first, am, "y")
							},
							b : {
								x : m.x,
								y : b.y + off(last, bm, "y")
							},
							z : this.getWeight(from, "r", to, "l", edge,
									a.x > b.x)
						});
			}

			// Checks |
			// +---+
			// |
			// V
			if (!ab.isIncluded(a.x, m.y) && !bb.isIncluded(b.x, m.y)) {
				positions.push({
							a : {
								x : a.x + off(first, am, "x"),
								y : m.y
							},
							b : {
								x : b.x + off(last, bm, "x"),
								y : m.y
							},
							z : this.getWeight(from, "b", to, "t", edge,
									a.y > b.y)
						});
			}

			// Sort DESC of weights
			return positions.sort(function(a, b) {
						return a.z < b.z ? 1 : (a.z == b.z ? -1 : -1)
					});
		},

		/**
		 * Returns a offset for the pos to the center of the bounds
		 * 
		 * @param {Object}
		 *            val
		 * @param {Object}
		 *            pos2
		 * @param {String}
		 *            dir Direction x|y
		 */
		getOffset : function(pos, pos2, dir) {
			return pos[dir] - pos2[dir];
		},

		/**
		 * Returns a value which shows the weight for this configuration
		 * 
		 * @param {Object}
		 *            from Shape which is coming from
		 * @param {String}
		 *            d1 Direction where is goes
		 * @param {Object}
		 *            to Shape which goes to
		 * @param {String}
		 *            d2 Direction where it comes to
		 * @param {Object}
		 *            edge Edge between from and to
		 * @param {Boolean}
		 *            reverse Reverse the direction (e.g. "r" -> "l")
		 */
		getWeight : function(from, d1, to, d2, edge, reverse) {

			d1 = (d1 || "").toLowerCase();
			d2 = (d2 || "").toLowerCase();

			if (!["t", "r", "b", "l"].include(d1)) {
				d1 = "r"
			}
			if (!["t", "r", "b", "l"].include(d2)) {
				d1 = "l"
			}

			// If reverse is set
			if (reverse) {
				// Reverse d1 and d2
				d1 = d1 == "t" ? "b" : (d1 == "r" ? "l" : (d1 == "b"
						? "t"
						: (d1 == "l" ? "r" : "r")))
				d2 = d2 == "t" ? "b" : (d2 == "r" ? "l" : (d2 == "b"
						? "t"
						: (d2 == "l" ? "r" : "r")))
			}

			var weight = 0;
			// Get rules for from "out" and to "in"
			var dr1 = this.facade.getRules().getLayoutingRules(from, edge)["out"];
			var dr2 = this.facade.getRules().getLayoutingRules(to, edge)["in"];

			var fromWeight = dr1[d1];
			var toWeight = dr2[d2];

			/**
			 * Return a true if the center 1 is in the same direction than
			 * center 2
			 * 
			 * @param {Object}
			 *            direction
			 * @param {Object}
			 *            center1
			 * @param {Object}
			 *            center2
			 */
			var sameDirection = function(direction, center1, center2) {
				switch (direction) {
					case "t" :
						return Math.abs(center1.x - center2.x) < 2
								&& center1.y < center2.y
					case "r" :
						return center1.x > center2.x
								&& Math.abs(center1.y - center2.y) < 2
					case "b" :
						return Math.abs(center1.x - center2.x) < 2
								&& center1.y > center2.y
					case "l" :
						return center1.x < center2.x
								&& Math.abs(center1.y - center2.y) < 2
					default :
						return false;
				}
			}

			// Check if there are same incoming edges from 'from'
			var sameIncomingFrom = from.getIncomingShapes().findAll(
					function(a) {
						return a instanceof ORYX.Core.Edge
					}).any(function(e) {
				return sameDirection(d1, e.dockers[e.dockers.length - 2].bounds
								.center(), e.dockers.last().bounds.center());
			});

			// Check if there are same outgoing edges from 'to'
			var sameOutgoingTo = to.getOutgoingShapes().findAll(function(a) {
						return a instanceof ORYX.Core.Edge
					}).any(function(e) {
				return sameDirection(d2, e.dockers[1].bounds.center(),
						e.dockers.first().bounds.center());
			});

			// If there are equivalent edges, set 0
			// fromWeight = sameIncomingFrom ? 0 : fromWeight;
			// toWeight = sameOutgoingTo ? 0 : toWeight;

			// Get the sum of "out" and the direction plus "in" and the
			// direction
			return (sameIncomingFrom || sameOutgoingTo ? 0 : fromWeight
					+ toWeight);
		},

		/**
		 * Removes all current dockers from the node (except the start and end)
		 * and adds two new dockers, on the position a and b.
		 * 
		 * @param {Object}
		 *            edge
		 * @param {Object}
		 *            a
		 * @param {Object}
		 *            b
		 */
		setDockers : function(edge, a, b) {
			if (!edge) {
				return
			}

			// Remove all dockers (implicit,
			// start and end dockers will not removed)
			edge.dockers.each(function(r) {
						edge.removeDocker(r);
					});

			// For a and b (if exists), create
			// a new docker and set position
			[a, b].compact().each(function(pos) {
						var docker = edge.createDocker(undefined, pos);
						docker.bounds.centerMoveTo(pos);
					});

			// Update all dockers from the edge
			edge.dockers.each(function(docker) {
						docker.update()
					})

			// Update edge
			// edge.refresh();
			edge._update(true);

		}
	});

}()
/*
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. License
 * rights for this program may be obtained from Alfresco Software, Ltd. pursuant
 * to a written agreement and any use of this program without such an agreement
 * is prohibited.
 */
/*
 * All code Copyright 2013 KIS Consultancy all rights reserved
 */

if (!ORYX.Plugins)
	ORYX.Plugins = new Object();

new function() {

	ORYX.Plugins.BPMN2_0 = {

		/**
		 * Constructor
		 * 
		 * @param {Object}
		 *            Facade: The Facade of the Editor
		 */
		construct : function(facade) {
			this.facade = facade;

			this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED,
					this.handleDockerDocked.bind(this));
			this.facade.registerOnEvent(
					ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED,
					this.handlePropertyChanged.bind(this));
			this.facade.registerOnEvent('layout.bpmn2_0.pool',
					this.handleLayoutPool.bind(this));
			this.facade.registerOnEvent('layout.bpmn2_0.subprocess',
					this.handleSubProcess.bind(this));
			this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SHAPEREMOVED,
					this.handleShapeRemove.bind(this));

			this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED,
					this.afterLoad.bind(this));

			this.namespace = undefined;
		},

		/**
		 * Force to update every pool
		 */
		afterLoad : function() {
			this.facade.getCanvas().getChildNodes().each(function(shape) {
						if (shape.getStencil().id().endsWith("Pool")) {
							this.handleLayoutPool({
										shape : shape
									});
						}
					}.bind(this))
		},

		/**
		 * If a pool is selected and contains no lane, a lane is created
		 * automagically
		 */
		onSelectionChanged : function(event) {
			var selection = event.elements;

			if (selection && selection.length === 1) {
				var namespace = this.getNamespace();
				var shape = selection[0];
				if (shape.getStencil().idWithoutNs() === "Pool") {
					if (shape.getChildNodes().length === 0) {
						// create a lane inside the selected pool
						var option = {
							type : namespace + "Lane",
							position : {
								x : 0,
								y : 0
							},
							namespace : shape.getStencil().namespace(),
							parent : shape
						};
						this.facade.createShape(option);
						this.facade.getCanvas().update();
						this.facade.setSelection([shape]);
					}
				}
			}

			// Preventing selection of all lanes but not the pool
			if (selection.any(function(s) {
						return s instanceof ORYX.Core.Node
								&& s.getStencil().id().endsWith("Lane")
					})) {
				var lanes = selection.findAll(function(s) {
							return s instanceof ORYX.Core.Node
									&& s.getStencil().id().endsWith("Lane")
						});

				var pools = [];
				var unselectLanes = [];
				lanes.each(function(lane) {
							pools.push(this.getParentPool(lane))
						}.bind(this));

				pools = pools.uniq().findAll(function(pool) {
					var childLanes = this.getLanes(pool, true);
					if (childLanes.all(function(lane) {
								return lanes.include(lane)
							})) {
						unselectLanes = unselectLanes.concat(childLanes);
						return true;
					} else if (selection.include(pool)
							&& childLanes.any(function(lane) {
										return lanes.include(lane)
									})) {
						unselectLanes = unselectLanes.concat(childLanes);
						return true;
					} else {
						return false;
					}
				}.bind(this))

				if (unselectLanes.length > 0 && pools.length > 0) {
					selection = selection.without.apply(selection,
							unselectLanes);
					selection = selection.concat(pools);
					this.facade.setSelection(selection.uniq());
				}
			}
		},

		handleShapeRemove : function(option) {

			var sh = option.shape;
			var parent = option.parent;

			if (sh instanceof ORYX.Core.Node
					&& sh.getStencil().idWithoutNs() === "Lane"
					&& this.facade.isExecutingCommands()) {

				var pool = this.getParentPool(parent);
				if (pool && pool.parent) {

					var isLeafFn = function(leaf) {
						return !leaf.getChildNodes().any(function(r) {
									return r.getStencil().idWithoutNs() === "Lane"
								});
					}

					var isLeaf = isLeafFn(sh);
					var parentHasMoreLanes = parent.getChildNodes().any(
							function(r) {
								return r.getStencil().idWithoutNs() === "Lane"
							});

					if (isLeaf && parentHasMoreLanes) {

						var command = new ResizeLanesCommand(sh, parent, pool,
								this);
						this.facade.executeCommands([command]);

					} else if (!isLeaf
							&& !this.facade.getSelection().any(
									function(select) { // Find one of the
														// selection, which is a
														// lane and child of
														// "sh" and is a leaf
														// lane
										return select instanceof ORYX.Core.Node
												&& select.getStencil()
														.idWithoutNs() === "Lane"
												&& select.isParent(sh)
												&& isLeafFn(select);
									})) {

						var Command = ORYX.Core.Command.extend({
									construct : function(shape, facade) {
										this.children = shape
												.getChildNodes(true);
										this.facade = facade;
									},
									execute : function() {
										this.children.each(function(child) {
													child.bounds.moveBy(30, 0)
												});
										// this.facade.getCanvas().update();
									},
									rollback : function() {
										this.children.each(function(child) {
													child.bounds.moveBy(-30, 0)
												})
										// this.facade.getCanvas().update();
									}
								});
						this.facade.executeCommands([new Command(sh,
								this.facade)]);

					} else if (isLeaf && !parentHasMoreLanes && parent == pool) {
						parent.add(sh);
					}
				}

			}

		},

		hashedSubProcesses : {},

		hashChildShapes : function(shape) {
			var children = shape.getChildNodes();
			children.each(function(child) {
						if (this.hashedSubProcesses[child.id]) {
							this.hashedSubProcesses[child.id] = child
									.absoluteXY();
							this.hashedSubProcesses[child.id].width = child.bounds
									.width();
							this.hashedSubProcesses[child.id].height = child.bounds
									.height();
							this.hashChildShapes(child);
						}
					}.bind(this));
		},

		/**
		 * Handle the layouting of a sub process. Mainly to adjust the child
		 * dockers of a sub process.
		 * 
		 */
		handleSubProcess : function(option) {

			var sh = option.shape;

			if (!this.hashedSubProcesses[sh.id]) {
				this.hashedSubProcesses[sh.id] = sh.absoluteXY();
				this.hashedSubProcesses[sh.id].width = sh.bounds.width();
				this.hashedSubProcesses[sh.id].height = sh.bounds.height();
				return;
			}

			var offset = sh.absoluteXY();
			offset.x -= this.hashedSubProcesses[sh.id].x;
			offset.y -= this.hashedSubProcesses[sh.id].y;

			var resized = this.hashedSubProcesses[sh.id].width !== sh.bounds
					.width()
					|| this.hashedSubProcesses[sh.id].height !== sh.bounds
							.height();

			this.hashedSubProcesses[sh.id] = sh.absoluteXY();
			this.hashedSubProcesses[sh.id].width = sh.bounds.width();
			this.hashedSubProcesses[sh.id].height = sh.bounds.height();
			this.hashChildShapes(sh);

			// Move dockers only if currently is not resizing
			if (this.facade.isExecutingCommands() && !resized) {
				this.moveChildDockers(sh, offset);
			}
		},

		moveChildDockers : function(shape, offset) {

			if (!offset.x && !offset.y) {
				return;
			}

			var children = shape.getChildNodes(true);

			// Get all nodes
			var dockers = children
					// Get all incoming and outgoing edges
					.map(function(node) {
						return [].concat(node.getIncomingShapes()).concat(node
								.getOutgoingShapes())
					})
					// Flatten all including arrays into one
					.flatten()
					// Get every edge only once
					.uniq()
					// Get all dockers
					.map(function(edge) {
						return edge.dockers.length > 2 ? edge.dockers.slice(1,
								edge.dockers.length - 1) : [];
					})
					// Flatten the dockers lists
					.flatten();

			var abs = shape.absoluteBounds();
			abs.moveBy(-offset.x, -offset.y)
			var obj = {};
			dockers.each(function(docker) {

						if (docker.isChanged) {
							return;
						}

						var off = Object.clone(offset);

						if (!abs.isIncluded(docker.bounds.center())) {
							var index = docker.parent.dockers.indexOf(docker);
							var size = docker.parent.dockers.length;
							var from = docker.parent.getSource();
							var to = docker.parent.getTarget();

							var bothAreIncluded = children.include(from)
									&& children.include(to);

							if (!bothAreIncluded) {
								var previousIsOver = index !== 0 ? abs
										.isIncluded(docker.parent.dockers[index
												- 1].bounds.center()) : false;
								var nextIsOver = index !== size - 1 ? abs
										.isIncluded(docker.parent.dockers[index
												+ 1].bounds.center()) : false;

								if (!previousIsOver && !nextIsOver) {
									return;
								}

								var ref = docker.parent.dockers[previousIsOver
										? index - 1
										: index + 1];
								if (Math.abs(-Math.abs(ref.bounds.center().x
										- docker.bounds.center().x)) < 2) {
									off.y = 0;
								} else if (Math.abs(-Math.abs(ref.bounds
										.center().y
										- docker.bounds.center().y)) < 2) {
									off.x = 0;
								} else {
									return;
								}
							}

						}

						obj[docker.getId()] = {
							docker : docker,
							offset : off
						}
					})

			// Set dockers
			this.facade
					.executeCommands([new ORYX.Core.MoveDockersCommand(obj)]);

		},

		/**
		 * DragDocker.Docked Handler
		 * 
		 */
		handleDockerDocked : function(options) {
			var namespace = this.getNamespace();

			var edge = options.parent;
			var edgeSource = options.target;

			if (edge.getStencil().id() === namespace + "SequenceFlow") {
				var isGateway = edgeSource.getStencil().groups().find(
						function(group) {
							if (group == "Gateways")
								return group;
						});
				if (!isGateway
						&& (edge.properties["oryx-conditiontype"] == "Expression"))
					// show diamond on edge source
					edge.setProperty("oryx-showdiamondmarker", true);
				else
					// do not show diamond on edge source
					edge.setProperty("oryx-showdiamondmarker", false);

				// update edge rendering
				// edge.update();

				this.facade.getCanvas().update();
			}
		},

		/**
		 * PropertyWindow.PropertyChanged Handler
		 */
		handlePropertyChanged : function(option) {
			var namespace = this.getNamespace();

			var shapes = option.elements;
			var propertyKey = option.key;
			var propertyValue = option.value;

			var changed = false;
			shapes.each(function(shape) {
				if ((shape.getStencil().id() === namespace + "SequenceFlow")
						&& (propertyKey === "oryx-conditiontype")) {

					if (propertyValue != "Expression")
						// Do not show the Diamond
						shape.setProperty("oryx-showdiamondmarker", false);
					else {
						var incomingShapes = shape.getIncomingShapes();

						if (!incomingShapes) {
							shape.setProperty("oryx-showdiamondmarker", true);
						}

						var incomingGateway = incomingShapes.find(function(
										aShape) {
									var foundGateway = aShape.getStencil()
											.groups().find(function(group) {
														if (group == "Gateways")
															return group;
													});
									if (foundGateway)
										return foundGateway;
								});

						if (!incomingGateway)
							// show diamond on edge source
							shape.setProperty("oryx-showdiamondmarker", true);
						else
							// do not show diamond
							shape.setProperty("oryx-showdiamondmarker", false);
					}

					changed = true;
				}
			}.bind(this));

			if (changed) {
				this.facade.getCanvas().update();
			}

		},

		hashedPoolPositions : {},
		hashedLaneDepth : {},
		hashedBounds : {},
		hashedPositions : {},

		/**
		 * Handler for layouting event 'layout.bpmn2_0.pool'
		 * 
		 * @param {Object}
		 *            event
		 */
		handleLayoutPool : function(event) {

			var pool = event.shape;
			var selection = this.facade.getSelection();
			var currentShape = selection.include(pool) ? pool : selection
					.first();

			currentShape = currentShape || pool;

			this.currentPool = pool;

			// Check if it is a pool or a lane
			if (!(currentShape.getStencil().id().endsWith("Pool") || currentShape
					.getStencil().id().endsWith("Lane"))) {
				return;
			}

			// Check if the lane is within the pool and is not removed lately
			if (currentShape !== pool && !currentShape.isParent(pool)
					&& !this.hashedBounds[pool.id][currentShape.id]) {
				return;
			}

			if (!this.hashedBounds[pool.id]) {
				this.hashedBounds[pool.id] = {};
			}

			// Find all child lanes
			var lanes = this.getLanes(pool);

			if (lanes.length <= 0) {
				return
			}

			var allLanes = this.getLanes(pool, true), hp;
			var considerForDockers = allLanes.clone();

			var hashedPositions = $H({});
			allLanes.each(function(lane) {
						hashedPositions[lane.id] = lane.bounds.upperLeft();
					})

			// Show/hide caption regarding the number of lanes
			if (lanes.length === 1 && this.getLanes(lanes.first()).length <= 0) {
				// TRUE if there is a caption
				lanes
						.first()
						.setProperty(
								"oryx-showcaption",
								lanes.first().properties["oryx-name"].trim().length > 0);
				var rect = lanes.first().node.getElementsByTagName("rect");
				rect[0].setAttributeNS(null, "display", "none");
			} else {
				allLanes.invoke("setProperty", "oryx-showcaption", true);
				allLanes.each(function(lane) {
							var rect = lane.node.getElementsByTagName("rect");
							rect[0].removeAttributeNS(null, "display");
						})
			}

			var deletedLanes = [];
			var addedLanes = [];

			// Get all new lanes
			var i = -1;
			while (++i < allLanes.length) {
				if (!this.hashedBounds[pool.id][allLanes[i].id]) {
					addedLanes.push(allLanes[i])
				}
			}

			if (addedLanes.length > 0) {
				currentShape = addedLanes.first();
			}

			// Get all deleted lanes
			var resourceIds = $H(this.hashedBounds[pool.id]).keys();
			var i = -1;
			while (++i < resourceIds.length) {
				if (!allLanes.any(function(lane) {
							return lane.id == resourceIds[i]
						})) {
					deletedLanes
							.push(this.hashedBounds[pool.id][resourceIds[i]]);
					selection = selection.without(function(r) {
								return r.id == resourceIds[i]
							});
				}
			}

			var height, width, x, y;

			if (deletedLanes.length > 0 || addedLanes.length > 0) {

				if (addedLanes.length === 1
						&& this.getLanes(addedLanes[0].parent).length === 1) {
					// Set height from the pool
					height = this.adjustHeight(lanes, addedLanes[0].parent);
				} else {
					// Set height from the pool
					height = this.updateHeight(pool);
				}
				// Set width from the pool
				width = this.adjustWidth(lanes, pool.bounds.width());

				pool.update();
			}

			/**
			 * Set width/height depending on the pool
			 */
			else if (pool == currentShape) {

				if (selection.length === 1
						&& this.isResized(pool,
								this.hashedPoolPositions[pool.id])) {
					var oldXY = this.hashedPoolPositions[pool.id].upperLeft();
					var xy = pool.bounds.upperLeft();
					var scale = 0;
					if (this.shouldScale(pool)) {
						var old = this.hashedPoolPositions[pool.id];
						scale = old.height() / pool.bounds.height();
					}

					this.adjustLanes(pool, allLanes, oldXY.x - xy.x, oldXY.y
									- xy.y, scale);
				}

				// Set height from the pool
				height = this.adjustHeight(lanes, undefined, pool.bounds
								.height());
				// Set width from the pool
				width = this.adjustWidth(lanes, pool.bounds.width());
			}

			/**
			 * ??? Set width/height depending on containing lanes
			 */
			else {

				// Reposition the pool if one shape is selected and the
				// upperleft has changed
				if (selection.length === 1
						&& this.isResized(currentShape,
								this.hashedBounds[pool.id][currentShape.id])) {
					var oldXY = this.hashedBounds[pool.id][currentShape.id]
							.upperLeft();
					var xy = currentShape.absoluteXY();
					x = oldXY.x - xy.x;
					y = oldXY.y - xy.y;

					// Adjust all other lanes beneath this lane
					if (x || y) {
						considerForDockers = considerForDockers
								.without(currentShape);
						this.adjustLanes(pool, this.getAllExcludedLanes(pool,
										currentShape), x, 0);
					}

					// Adjust all child lanes
					var childLanes = this.getLanes(currentShape, true);
					if (childLanes.length > 0) {
						if (this.shouldScale(currentShape)) {
							var old = this.hashedBounds[pool.id][currentShape.id];
							var scale = old.height()
									/ currentShape.bounds.height();
							this.adjustLanes(pool, childLanes, x, y, scale);
						} else {
							this.adjustLanes(pool, childLanes, x, y, 0);
						}
					}
				}

				// Cache all bounds
				var changes = allLanes.map(function(lane) {
							return {
								shape : lane,
								bounds : lane.bounds.clone()
							}
						});

				// Get height and adjust child heights
				height = this.adjustHeight(lanes, currentShape);
				// Check if something has changed and maybe create a command
				this.checkForChanges(allLanes, changes);

				// Set width from the current shape
				width = this.adjustWidth(lanes, currentShape.bounds.width()
								+ (this.getDepth(currentShape, pool) * 30));
			}

			this.setDimensions(pool, width, height, x, y);

			if (this.facade.isExecutingCommands()
					&& (deletedLanes.length === 0 || addedLanes.length !== 0)) {
				// Update all dockers
				this.updateDockers(considerForDockers, pool);

				// Check if the order has changed
				if (this.hashedPositions[pool.id]
						&& this.hashedPositions[pool.id].keys().any(
								function(key, i) {
									return (allLanes[i] || {}).id !== key;
								})) {

					var LanesHasBeenReordered = ORYX.Core.Command.extend({
						construct : function(originPosition, newPosition,
								lanes, plugin, poolId) {
							this.originPosition = Object.clone(originPosition);
							this.newPosition = Object.clone(newPosition);
							this.lanes = lanes;
							this.plugin = plugin;
							this.pool = poolId;
						},
						execute : function() {
							if (!this.executed) {
								this.executed = true;
								this.lanes.each(function(lane) {
									if (this.newPosition[lane.id])
										lane.bounds
												.moveTo(this.newPosition[lane.id])
								}.bind(this));
								this.plugin.hashedPositions[this.pool] = Object
										.clone(this.newPosition);
							}
						},
						rollback : function() {
							this.lanes.each(function(lane) {
								if (this.originPosition[lane.id])
									lane.bounds
											.moveTo(this.originPosition[lane.id])
							}.bind(this));
							this.plugin.hashedPositions[this.pool] = Object
									.clone(this.originPosition);
						}
					});

					var hp2 = $H({});
					allLanes.each(function(lane) {
								hp2[lane.id] = lane.bounds.upperLeft();
							})

					var command = new LanesHasBeenReordered(hashedPositions,
							hp2, allLanes, this, pool.id);
					this.facade.executeCommands([command]);

				}
			}

			this.hashedBounds[pool.id] = {};
			this.hashedPositions[pool.id] = hashedPositions;

			var i = -1;
			while (++i < allLanes.length) {
				// Cache positions
				this.hashedBounds[pool.id][allLanes[i].id] = allLanes[i]
						.absoluteBounds();

				// Cache also the bounds of child shapes, mainly for child
				// subprocesses
				this.hashChildShapes(allLanes[i]);

				this.hashedLaneDepth[allLanes[i].id] = this.getDepth(
						allLanes[i], pool);

				this.forceToUpdateLane(allLanes[i]);
			}

			this.hashedPoolPositions[pool.id] = pool.bounds.clone();

			// Update selection
			// this.facade.setSelection(selection);
		},

		shouldScale : function(element) {
			var childLanes = element.getChildNodes().findAll(function(shape) {
						return shape.getStencil().id().endsWith("Lane")
					})
			return childLanes.length > 1 || childLanes.any(function(lane) {
						return this.shouldScale(lane)
					}.bind(this))
		},

		/**
		 * Lookup if some bounds has changed
		 * 
		 * @param {Object}
		 *            lanes
		 * @param {Object}
		 *            changes
		 */
		checkForChanges : function(lanes, changes) {
			// Check if something has changed
			if (this.facade.isExecutingCommands()
					&& changes.any(function(change) {
								return change.shape.bounds.toString() !== change.bounds
										.toString();
							})) {

				var Command = ORYX.Core.Command.extend({
							construct : function(changes) {
								this.oldState = changes;
								this.newState = changes.map(function(s) {
											return {
												shape : s.shape,
												bounds : s.bounds.clone()
											}
										});
							},
							execute : function() {
								if (this.executed) {
									this.applyState(this.newState);
								}
								this.executed = true;
							},
							rollback : function() {
								this.applyState(this.oldState);
							},
							applyState : function(state) {
								state.each(function(s) {
											s.shape.bounds.set(s.bounds
															.upperLeft(),
													s.bounds.lowerRight());
										})
							}
						});

				this.facade.executeCommands([new Command(changes)]);
			}
		},

		isResized : function(shape, bounds) {

			if (!bounds || !shape) {
				return false;
			}

			var oldB = bounds;
			// var oldXY = oldB.upperLeft();
			// var xy = shape.absoluteXY();
			return Math.round(oldB.width() - shape.bounds.width()) !== 0
					|| Math.round(oldB.height() - shape.bounds.height()) !== 0
		},

		adjustLanes : function(pool, lanes, x, y, scale) {

			scale = scale || 0;

			// For every lane, adjust the child nodes with the offset
			lanes.each(function(l) {
						l.getChildNodes().each(function(child) {
							if (!child.getStencil().id().endsWith("Lane")) {
								var cy = scale
										? child.bounds.center().y
												- (child.bounds.center().y / scale)
										: -y;
								child.bounds.moveBy((x || 0), -cy);

								if (scale
										&& child.getStencil().id()
												.endsWith("Subprocess")) {
									this.moveChildDockers(child, {
												x : (0),
												y : -cy
											});
								}

							}
						}.bind(this));
						this.hashedBounds[pool.id][l.id].moveBy(-(x || 0),
								!scale ? -y : 0);
						if (scale) {
							l.isScaled = true;
						}
					}.bind(this))

		},

		getAllExcludedLanes : function(parent, lane) {
			var lanes = [];
			parent.getChildNodes().each(function(shape) {
				if ((!lane || shape !== lane)
						&& shape.getStencil().id().endsWith("Lane")) {
					lanes.push(shape);
					lanes = lanes.concat(this.getAllExcludedLanes(shape, lane));
				}
			}.bind(this));
			return lanes;
		},

		forceToUpdateLane : function(lane) {

			if (lane.bounds.height() !== lane._svgShapes[0].height) {
				lane.isChanged = true;
				lane.isResized = true;
				lane._update();
			}
		},

		getDepth : function(child, parent) {

			var i = 0;
			while (child && child.parent && child !== parent) {
				child = child.parent;
				++i
			}
			return i;
		},

		updateDepth : function(lane, fromDepth, toDepth) {

			var xOffset = (fromDepth - toDepth) * 30;

			lane.getChildNodes().each(function(shape) {
				shape.bounds.moveBy(xOffset, 0);

				[].concat(children[j].getIncomingShapes()).concat(children[j]
						.getOutgoingShapes())

			})

		},

		setDimensions : function(shape, width, height, x, y) {
			var isLane = shape.getStencil().id().endsWith("Lane");
			// Set the bounds
			shape.bounds.set(isLane ? 30 : (shape.bounds.a.x - (x || 0)),
					isLane ? shape.bounds.a.y : (shape.bounds.a.y - (y || 0)),
					width
							? shape.bounds.a.x + width
									- (isLane ? 30 : (x || 0))
							: shape.bounds.b.x, height
							? shape.bounds.a.y + height
									- (isLane ? 0 : (y || 0))
							: shape.bounds.b.y);
		},

		setLanePosition : function(shape, y) {

			shape.bounds.moveTo(30, y);

		},

		adjustWidth : function(lanes, width) {

			// Set width to each lane
			(lanes || []).each(function(lane) {
						this.setDimensions(lane, width);
						this.adjustWidth(this.getLanes(lane), width - 30);
					}.bind(this));

			return width;
		},

		adjustHeight : function(lanes, changedLane, propagateHeight) {

			var oldHeight = 0;
			if (!changedLane && propagateHeight) {
				var i = -1;
				while (++i < lanes.length) {
					oldHeight += lanes[i].bounds.height();
				}
			}

			var i = -1;
			var height = 0;

			// Iterate trough every lane
			while (++i < lanes.length) {

				if (lanes[i] === changedLane) {
					// Propagate new height down to the children
					this.adjustHeight(this.getLanes(lanes[i]), undefined,
							lanes[i].bounds.height());

					lanes[i].bounds.set({
								x : 30,
								y : height
							}, {
								x : lanes[i].bounds.width() + 30,
								y : lanes[i].bounds.height() + height
							})

				} else if (!changedLane && propagateHeight) {

					var tempHeight = (lanes[i].bounds.height() * propagateHeight)
							/ oldHeight;
					// Propagate height
					this.adjustHeight(this.getLanes(lanes[i]), undefined,
							tempHeight);
					// Set height propotional to the propagated and old height
					this.setDimensions(lanes[i], null, tempHeight);
					this.setLanePosition(lanes[i], height);
				} else {
					// Get height from children
					var tempHeight = this.adjustHeight(this.getLanes(lanes[i]),
							changedLane, propagateHeight);
					if (!tempHeight) {
						tempHeight = lanes[i].bounds.height();
					}
					this.setDimensions(lanes[i], null, tempHeight);
					this.setLanePosition(lanes[i], height);
				}

				height += lanes[i].bounds.height();
			}

			return height;

		},

		updateHeight : function(root) {

			var lanes = this.getLanes(root);

			if (lanes.length == 0) {
				return root.bounds.height();
			}

			var height = 0;
			var i = -1;
			while (++i < lanes.length) {
				this.setLanePosition(lanes[i], height);
				height += this.updateHeight(lanes[i]);
			}

			this.setDimensions(root, null, height);

			return height;
		},

		getOffset : function(lane, includePool, pool) {

			var offset = {
				x : 0,
				y : 0
			};

			/*
			 * var parent = lane; while(parent) {
			 * 
			 * 
			 * var offParent = this.hashedBounds[pool.id][parent.id]
			 * ||(includePool === true ? this.hashedPoolPositions[parent.id] :
			 * undefined); if (offParent){ var ul = parent.bounds.upperLeft();
			 * var ulo = offParent.upperLeft(); offset.x += ul.x-ulo.x; offset.y +=
			 * ul.y-ulo.y; }
			 * 
			 * if (parent.getStencil().id().endsWith("Pool")) { break; }
			 * 
			 * parent = parent.parent; }
			 */

			var offset = lane.absoluteXY();

			var hashed = this.hashedBounds[pool.id][lane.id]
					|| (includePool === true
							? this.hashedPoolPositions[lane.id]
							: undefined);
			if (hashed) {
				offset.x -= hashed.upperLeft().x;
				offset.y -= hashed.upperLeft().y;
			} else {
				return {
					x : 0,
					y : 0
				}
			}
			return offset;
		},

		getNextLane : function(shape) {
			while (shape && !shape.getStencil().id().endsWith("Lane")) {
				if (shape instanceof ORYX.Core.Canvas) {
					return null;
				}
				shape = shape.parent;
			}
			return shape;
		},

		getParentPool : function(shape) {
			while (shape && !shape.getStencil().id().endsWith("Pool")) {
				if (shape instanceof ORYX.Core.Canvas) {
					return null;
				}
				shape = shape.parent;
			}
			return shape;
		},

		updateDockers : function(lanes, pool) {

			var absPool = pool.absoluteBounds(), movedShapes = [];
			var oldPool = (this.hashedPoolPositions[pool.id] || absPool)
					.clone();

			var i = -1, j = -1, k = -1, l = -1, docker;
			var dockers = {};

			while (++i < lanes.length) {

				if (!this.hashedBounds[pool.id][lanes[i].id]) {
					continue;
				}

				var isScaled = lanes[i].isScaled;
				delete lanes[i].isScaled;
				var children = lanes[i].getChildNodes();
				var absBounds = lanes[i].absoluteBounds();
				var oldBounds = (this.hashedBounds[pool.id][lanes[i].id] || absBounds);
				// oldBounds.moveBy((absBounds.upperLeft().x-lanes[i].bounds.upperLeft().x),
				// (absBounds.upperLeft().y-lanes[i].bounds.upperLeft().y));
				var offset = this.getOffset(lanes[i], true, pool);
				var xOffsetDepth = 0;

				var depth = this.getDepth(lanes[i], pool);
				if (this.hashedLaneDepth[lanes[i].id] !== undefined
						&& this.hashedLaneDepth[lanes[i].id] !== depth) {
					xOffsetDepth = (this.hashedLaneDepth[lanes[i].id] - depth)
							* 30;
					offset.x += xOffsetDepth;
				}

				j = -1;

				while (++j < children.length) {

					if (xOffsetDepth
							&& !children[j].getStencil().id().endsWith("Lane")) {
						movedShapes.push({
									xOffset : xOffsetDepth,
									shape : children[j]
								});
						children[j].bounds.moveBy(xOffsetDepth, 0);
					}

					if (children[j].getStencil().id().endsWith("Subprocess")) {
						this.moveChildDockers(children[j], offset);
					}

					var edges = [].concat(children[j].getIncomingShapes())
							.concat(children[j].getOutgoingShapes())
							// Remove all edges which are included in the
							// selection from the list
							.findAll(function(r) {
										return r instanceof ORYX.Core.Edge
									})

					k = -1;
					while (++k < edges.length) {

						if (edges[k].getStencil().id().endsWith("MessageFlow")) {
							this.layoutEdges(children[j], [edges[k]], offset);
							continue;
						}

						l = -1;
						while (++l < edges[k].dockers.length) {

							docker = edges[k].dockers[l];

							if (docker.getDockedShape() || docker.isChanged) {
								continue;
							}

							pos = docker.bounds.center();

							// Check if the modified center included the new
							// position
							var isOverLane = oldBounds.isIncluded(pos);
							// Check if the original center is over the pool
							var isOutSidePool = !oldPool.isIncluded(pos);
							var previousIsOverLane = l == 0
									? isOverLane
									: oldBounds.isIncluded(edges[k].dockers[l
											- 1].bounds.center());
							var nextIsOverLane = l == edges[k].dockers.length
									- 1 ? isOverLane : oldBounds
									.isIncluded(edges[k].dockers[l + 1].bounds
											.center());
							var off = Object.clone(offset);

							// If the
							if (isScaled
									&& isOverLane
									&& this
											.isResized(
													lanes[i],
													this.hashedBounds[pool.id][lanes[i].id])) {
								var relY = (pos.y - absBounds.upperLeft().y + off.y);
								off.y -= (relY - (relY * (absBounds.height() / oldBounds
										.height())));
							}

							// Check if the previous dockers docked shape is
							// from this lane
							// Otherwise, check if the docker is over the lane
							// OR is outside the lane
							// but the previous/next was over this lane
							if (isOverLane) {
								dockers[docker.id] = {
									docker : docker,
									offset : off
								};
							}
							/*
							 * else if (l == 1 && edges[k].dockers.length>2 &&
							 * edges[k].dockers[l-1].isDocked()){ var dockedLane =
							 * this.getNextLane(edges[k].dockers[l-1].getDockedShape());
							 * if (dockedLane != lanes[i]) continue;
							 * dockers[docker.id] = {docker: docker,
							 * offset:offset}; } // Check if the next dockers
							 * docked shape is from this lane else if (l ==
							 * edges[k].dockers.length-2 &&
							 * edges[k].dockers.length>2 &&
							 * edges[k].dockers[l+1].isDocked()){ var dockedLane =
							 * this.getNextLane(edges[k].dockers[l+1].getDockedShape());
							 * if (dockedLane != lanes[i]) continue;
							 * dockers[docker.id] = {docker: docker,
							 * offset:offset}; }
							 * 
							 * else if (isOutSidePool) { dockers[docker.id] =
							 * {docker: docker, offset:this.getOffset(lanes[i],
							 * true, pool)}; }
							 */

						}
					}

				}
			}

			// Move the moved children
			var MoveChildCommand = ORYX.Core.Command.extend({
						construct : function(state) {
							this.state = state;
						},
						execute : function() {
							if (this.executed) {
								this.state.each(function(s) {
											s.shape.bounds.moveBy(s.xOffset, 0);
										});
							}
							this.executed = true;
						},
						rollback : function() {
							this.state.each(function(s) {
										s.shape.bounds.moveBy(-s.xOffset, 0);
									});
						}
					})

			// Set dockers
			this.facade.executeCommands([
					new ORYX.Core.MoveDockersCommand(dockers),
					new MoveChildCommand(movedShapes)]);

		},

		moveBy : function(pos, offset) {
			pos.x += offset.x;
			pos.y += offset.y;
			return pos;
		},

		getHashedBounds : function(shape) {
			return this.currentPool
					&& this.hashedBounds[this.currentPool.id][shape.id]
					? this.hashedBounds[this.currentPool.id][shape.id]
					: shape.absoluteBounds();
		},

		/**
		 * Returns a set on all child lanes for the given Shape. If recursive is
		 * TRUE, also indirect children will be returned (default is FALSE) The
		 * set is sorted with first child the lowest y-coordinate and the last
		 * one the highest.
		 * 
		 * @param {ORYX.Core.Shape}
		 *            shape
		 * @param {boolean}
		 *            recursive
		 */
		getLanes : function(shape, recursive) {
			var namespace = this.getNamespace();

			// Get all the child lanes
			var lanes = shape.getChildNodes(recursive || false).findAll(
					function(node) {
						return (node.getStencil().id() === namespace + "Lane");
					});

			// Sort all lanes by there y coordinate
			lanes = lanes.sort(function(a, b) {

						// Get y coordinates for upper left and lower right
						var auy = Math.round(a.bounds.upperLeft().y);
						var buy = Math.round(b.bounds.upperLeft().y);
						var aly = Math.round(a.bounds.lowerRight().y);
						var bly = Math.round(b.bounds.lowerRight().y);

						var ha = this.getHashedBounds(a);
						var hb = this.getHashedBounds(b);

						// Get the old y coordinates
						var oauy = Math.round(ha.upperLeft().y);
						var obuy = Math.round(hb.upperLeft().y);
						var oaly = Math.round(ha.lowerRight().y);
						var obly = Math.round(hb.lowerRight().y);

						// If equal, than use the old one
						if (auy == buy && aly == bly) {
							auy = oauy;
							buy = obuy;
							aly = oaly;
							bly = obly;
						}

						if (Math.round(a.bounds.height() - ha.height()) === 0
								&& Math.round(b.bounds.height() - hb.height()) === 0) {
							return auy < buy ? -1 : (auy > buy ? 1 : 0);
						}

						// Check if upper left and lower right is completely
						// above/below
						var above = auy < buy && aly < bly;
						var below = auy > buy && aly > bly;
						// Check if a is above b including the old values
						var slightlyAboveBottom = auy < buy && aly >= bly
								&& oaly < obly;
						var slightlyAboveTop = auy >= buy && aly < bly
								&& oauy < obuy;
						// Check if a is below b including the old values
						var slightlyBelowBottom = auy > buy && aly <= bly
								&& oaly > obly;
						var slightlyBelowTop = auy <= buy && aly > bly
								&& oauy > obuy;

						// Return -1 if a is above b, 1 if b is above a, or 0
						// otherwise
						return (above || slightlyAboveBottom
								|| slightlyAboveTop ? -1 : (below
								|| slightlyBelowBottom || slightlyBelowTop
								? 1
								: 0))
					}.bind(this));

			// Return lanes
			return lanes;
		},

		getNamespace : function() {
			if (!this.namespace) {
				var stencilsets = this.facade.getStencilSets();
				if (stencilsets.keys()) {
					this.namespace = stencilsets.keys()[0];
				} else {
					return undefined;
				}
			}
			return this.namespace;
		}
	};

	var ResizeLanesCommand = ORYX.Core.Command.extend({

		construct : function(shape, parent, pool, plugin) {

			this.facade = plugin.facade;
			this.plugin = plugin;
			this.shape = shape;
			this.changes;

			this.pool = pool;

			this.parent = parent;

			this.shapeChildren = [];

			/*
			 * The Bounds have to be stored separate because they would
			 * otherwise also be influenced
			 */
			this.shape.getChildShapes().each(function(childShape) {
						this.shapeChildren.push({
									shape : childShape,
									bounds : {
										a : {
											x : childShape.bounds.a.x,
											y : childShape.bounds.a.y
										},
										b : {
											x : childShape.bounds.b.x,
											y : childShape.bounds.b.y
										}
									}
								});
					}.bind(this));

			this.shapeUpperLeft = this.shape.bounds.upperLeft();

			// If there is no parent,
			// correct the abs position with the parents abs.
			/*
			 * if (!this.shape.parent) { var pAbs = parent.absoluteXY();
			 * this.shapeUpperLeft.x += pAbs.x; this.shapeUpperLeft.y += pAbs.y; }
			 */
			this.parentHeight = this.parent.bounds.height();

		},

		getLeafLanes : function(lane) {
			var childLanes = this.plugin.getLanes(lane).map(function(child) {
						return this.getLeafLanes(child);
					}.bind(this)).flatten();
			return childLanes.length > 0 ? childLanes : [lane];
		},

		findNewLane : function() {

			var lanes = this.plugin.getLanes(this.parent);

			var leafLanes = this.getLeafLanes(this.parent);
			/*
			 * leafLanes = leafLanes.sort(function(a,b){ var aupl =
			 * a.absoluteXY().y; var bupl = b.absoluteXY().y; return aupl < bupl ?
			 * -1 : (aupl > bupl ? 1 : 0) })
			 */
			this.lane = leafLanes.find(function(l) {
						return l.bounds.upperLeft().y >= this.shapeUpperLeft.y
					}.bind(this)) || leafLanes.last();
			this.laneUpperLeft = this.lane.bounds.upperLeft();
		},

		execute : function() {

			if (this.changes) {
				this.executeAgain();
				return;
			}

			/*
			 * Rescue all ChildShapes of the deleted Shape into the lane that
			 * takes its place
			 */

			if (!this.lane) {
				this.findNewLane();
			}

			if (this.lane) {

				var laUpL = this.laneUpperLeft;
				var shUpL = this.shapeUpperLeft;

				var depthChange = this.plugin.getDepth(this.lane, this.parent)
						- 1;

				this.changes = $H({});

				// Selected lane is BELOW the removed lane
				if (laUpL.y >= shUpL.y) {
					this.lane.getChildShapes().each(function(childShape) {

						/*
						 * Cache the changes for rollback
						 */
						if (!this.changes[childShape.getId()]) {
							this.changes[childShape.getId()] = this
									.computeChanges(childShape, this.lane,
											this.lane, this.shape.bounds
													.height());
						}

						childShape.bounds.moveBy(0, this.shape.bounds.height());
					}.bind(this));

					this.plugin.hashChildShapes(this.lane);

					this.shapeChildren.each(function(shapeChild) {
								shapeChild.shape.bounds.set(shapeChild.bounds);
								shapeChild.shape.bounds.moveBy((shUpL.x - 30)
												- (depthChange * 30), 0);

								/*
								 * Cache the changes for rollback
								 */
								if (!this.changes[shapeChild.shape.getId()]) {
									this.changes[shapeChild.shape.getId()] = this
											.computeChanges(shapeChild.shape,
													this.shape, this.lane, 0);
								}

								this.lane.add(shapeChild.shape);

							}.bind(this));

					this.lane.bounds.moveBy(0, shUpL.y - laUpL.y);

					// Selected lane is ABOVE the removed lane
				} else if (shUpL.y > laUpL.y) {

					this.shapeChildren.each(function(shapeChild) {
								shapeChild.shape.bounds.set(shapeChild.bounds);
								shapeChild.shape.bounds.moveBy((shUpL.x - 30)
												- (depthChange * 30),
										this.lane.bounds.height());

								/*
								 * Cache the changes for rollback
								 */
								if (!this.changes[shapeChild.shape.getId()]) {
									this.changes[shapeChild.shape.getId()] = this
											.computeChanges(shapeChild.shape,
													this.shape, this.lane, 0);
								}

								this.lane.add(shapeChild.shape);

							}.bind(this));
				}

			}

			/*
			 * Adjust the height of the lanes
			 */
			// Get the height values
			var oldHeight = this.lane.bounds.height();
			var newHeight = this.lane.length === 1
					? this.parentHeight
					: this.lane.bounds.height() + this.shape.bounds.height();

			// Set height
			this.setHeight(newHeight, oldHeight, this.parent,
					this.parentHeight, true);

			// Cache all sibling lanes
			// this.changes[this.shape.getId()] =
			// this.computeChanges(this.shape, this.parent, this.parent, 0);
			this.plugin.getLanes(this.parent).each(function(childLane) {
				if (!this.changes[childLane.getId()] && childLane !== this.lane
						&& childLane !== this.shape) {
					this.changes[childLane.getId()] = this.computeChanges(
							childLane, this.parent, this.parent, 0);
				}
			}.bind(this))

			// Update
			this.update();
		},

		setHeight : function(newHeight, oldHeight, parent, parentHeight, store) {

			// Set heigh of the lane
			this.plugin.setDimensions(this.lane, this.lane.bounds.width(),
					newHeight);
			this.plugin.hashedBounds[this.pool.id][this.lane.id] = this.lane
					.absoluteBounds();

			// Adjust child lanes
			this.plugin.adjustHeight(this.plugin.getLanes(parent), this.lane);

			if (store === true) {
				// Store changes
				this.changes[this.shape.getId()] = this.computeChanges(
						this.shape, parent, parent, 0, oldHeight, newHeight);
			}

			// Set parents height
			this.plugin.setDimensions(parent, parent.bounds.width(),
					parentHeight);

			if (parent !== this.pool) {
				this.plugin.setDimensions(this.pool, this.pool.bounds.width(),
						this.pool.bounds.height() + (newHeight - oldHeight));
			}
		},

		update : function() {

			// Hack to prevent the updating of the dockers
			this.plugin.hashedBounds[this.pool.id]["REMOVED"] = true;
			// Update
			// this.facade.getCanvas().update();
		},

		rollback : function() {

			var laUpL = this.laneUpperLeft;
			var shUpL = this.shapeUpperLeft;

			this.changes.each(function(pair) {

						var parent = pair.value.oldParent;
						var shape = pair.value.shape;
						var parentHeight = pair.value.parentHeight;
						var oldHeight = pair.value.oldHeight;
						var newHeight = pair.value.newHeight;

						// Move siblings
						if (shape.getStencil().id().endsWith("Lane")) {
							shape.bounds.moveTo(pair.value.oldPosition);
						}

						// If lane
						if (oldHeight) {
							this.setHeight(oldHeight, newHeight, parent,
									parent.bounds.height()
											+ (oldHeight - newHeight));
							if (laUpL.y >= shUpL.y) {
								this.lane.bounds.moveBy(0, this.shape.bounds
												.height()
												- 1);
							}
						} else {
							parent.add(shape);
							shape.bounds.moveTo(pair.value.oldPosition);

						}

					}.bind(this));

			// Update
			// this.update();

		},

		executeAgain : function() {

			this.changes.each(function(pair) {
						var parent = pair.value.newParent;
						var shape = pair.value.shape;
						var newHeight = pair.value.newHeight;
						var oldHeight = pair.value.oldHeight;

						// If lane
						if (newHeight) {
							var laUpL = this.laneUpperLeft.y;
							var shUpL = this.shapeUpperLeft.y;

							if (laUpL >= shUpL) {
								this.lane.bounds.moveBy(0, shUpL - laUpL);
							}
							this.setHeight(newHeight, oldHeight, parent,
									parent.bounds.height()
											+ (newHeight - oldHeight));
						} else {
							parent.add(shape);
							shape.bounds.moveTo(pair.value.newPosition);
						}

					}.bind(this));

			// Update
			this.update();
		},

		computeChanges : function(shape, oldParent, parent, yOffset, oldHeight,
				newHeight) {

			oldParent = this.changes[shape.getId()] ? this.changes[shape
					.getId()].oldParent : oldParent;
			var oldPosition = this.changes[shape.getId()] ? this.changes[shape
					.getId()].oldPosition : shape.bounds.upperLeft();

			var sUl = shape.bounds.upperLeft();

			var pos = {
				x : sUl.x,
				y : sUl.y + yOffset
			};

			var changes = {
				shape : shape,
				parentHeight : oldParent.bounds.height(),
				oldParent : oldParent,
				oldPosition : oldPosition,
				oldHeight : oldHeight,
				newParent : parent,
				newPosition : pos,
				newHeight : newHeight
			};

			return changes;
		}

	});

	ORYX.Plugins.BPMN2_0 = ORYX.Plugins.AbstractPlugin
			.extend(ORYX.Plugins.BPMN2_0);

}()